Close Menu
Cryprovideos
    What's Hot

    President Trump Will Print Enough Money To Pump Bitcoin to $1,000,000 by 2028: Arthur Hayes – The Daily Hodl

    May 15, 2025

    JPMorgan bridges blockchain and conventional finance in landmark pilot transaction

    May 15, 2025

    LangChain's Interrupt 2025: A New Period for AI Brokers

    May 15, 2025
    Facebook X (Twitter) Instagram
    Cryprovideos
    • Home
    • Crypto News
    • Bitcoin
    • Altcoins
    • Markets
    Cryprovideos
    Home»Markets»This Easy Candle Sample Technique Delivered 65% Win Fee in Backtesting
    This Easy Candle Sample Technique Delivered 65% Win Fee in Backtesting
    Markets

    This Easy Candle Sample Technique Delivered 65% Win Fee in Backtesting

    By Crypto EditorDecember 2, 2024No Comments8 Mins Read
    Share
    Facebook Twitter LinkedIn Pinterest Email


    I backtested a candle sample revealed by Michael Harris, exhibiting optimistic outcomes

    This Easy Candle Sample Technique Delivered 65% Win Fee in Backtesting
    The Capital

    Algorithmic buying and selling fanatics are at all times looking for strong methods, and candle patterns are a timeless favourite. On this article, we’ll undergo a robust sample from Michael Harris’s guide, examined rigorously utilizing Python. This straightforward but efficient technique demonstrated a 65% win price and a 71% revenue on main shares just like the S&P 500. With step-by-step coding steering and insights into the entry standards, it is a must-read for anybody seeking to elevate their buying and selling recreation utilizing automation.

    The total backtest outcomes will probably be introduced within the following fairness chart:

    import pandas as pd
    import pandas_ta as ta
    from tqdm import tqdm
    import os
    import numpy as np
    import plotly.graph_objects as go
    from plotly.subplots import make_subplots

    tqdm.pandas()

    def read_csv_to_dataframe(file_path):
    df = pd.read_csv(file_path)
    df["Gmt time"] = df["Gmt time"].str.exchange(".000", "")
    df['Gmt time'] = pd.to_datetime(df['Gmt time'], format='%d.%m.%Y %H:%M:%S')
    df = df[df.High != df.Low]
    df.set_index("Gmt time", inplace=True)
    return df

    def read_data_folder(folder_path="./information"):
    dataframes = []
    file_names = []
    for file_name in tqdm(os.listdir(folder_path)):
    if file_name.endswith('.csv'):
    file_path = os.path.be part of(folder_path, file_name)
    df = read_csv_to_dataframe(file_path)
    dataframes.append(df)
    file_names.append(file_name)
    return dataframes, file_names

    Step one in any backtesting challenge is to arrange the info, and this Python script ensures the info is clear and structured for evaluation. The code imports important libraries like pandas for information manipulation, pandas_ta for technical evaluation indicators, and plotly for visualization.

    • The read_csv_to_dataframe perform processes particular person CSV information, making certain timestamps are correctly formatted and invalid rows (the place Excessive equals Low) are eliminated.
    • The read_data_folder perform scans a folder of CSV information, processes them utilizing read_csv_to_dataframe, and returns an inventory of cleaned dataframes together with their filenames. This perform is used when we have to run the technique on multiple asset for instance utilizing a number of information information.
    • Using tqdm supplies a progress bar, making it straightforward to observe the processing of enormous datasets.

    The information information I used and the complete python code with a video walk-through can be found on YouTube should you want extra particulars:

    def total_signal(df, current_candle):
    current_pos = df.index.get_loc(current_candle)

    c1 = df['High'].iloc[current_pos] > df['Close'].iloc[current_pos]
    c2 = df['Close'].iloc[current_pos] > df['High'].iloc[current_pos-2]
    c3 = df['High'].iloc[current_pos-2] > df['High'].iloc[current_pos-1]
    c4 = df['High'].iloc[current_pos-1] > df['Low'].iloc[current_pos]
    c5 = df['Low'].iloc[current_pos] > df['Low'].iloc[current_pos-2]
    c6 = df['Low'].iloc[current_pos-2] > df['Low'].iloc[current_pos-1]

    if c1 and c2 and c3 and c4 and c5 and c6:
    return 2

    # Add the symmetrical situations for brief (go quick) if wanted
    c1 = df['Low'].iloc[current_pos] < df['Open'].iloc[current_pos]
    c2 = df['Open'].iloc[current_pos] < df['Low'].iloc[current_pos-2]
    c3 = df['Low'].iloc[current_pos-2] < df['Low'].iloc[current_pos-1]
    c4 = df['Low'].iloc[current_pos-1] < df['High'].iloc[current_pos]
    c5 = df['High'].iloc[current_pos] < df['High'].iloc[current_pos-2]
    c6 = df['High'].iloc[current_pos-2] < df['High'].iloc[current_pos-1]

    if c1 and c2 and c3 and c4 and c5 and c6:
    return 1

    return 0

    This step defines the core of the technique by figuring out the precise candle sample that indicators entry factors. The perform total_signal evaluates whether or not the situations for a sample are met for a given candle.

    Key elements of the sample logic:

    • Present Candle Place: Utilizing df.index.get_loc(current_candle), the perform identifies the place of the present candle within the DataFrame.

    Situations for Lengthy Entry:

    • Situation 1: The excessive of the present candle is larger than its closing value, indicating an higher wick.
    • Situation 2: The closing value of the present candle is larger than the excessive of the candle at place -2.
    • Situation 3: The excessive of the candle at place -2 is larger than the excessive of the candle at place -1.
    • Situation 4: The excessive of the candle at place -1 is larger than the low of the present candle.
    • Situation 5: The low of the present candle is larger than the low of the candle at place -2.
    • Situation 6: The low of the candle at place -2 is larger than the low of the candle at place -1.

    Situations for Brief Entry:

    • Symmetrical to the lengthy entry logic, specializing in decrease wicks and downward momentum.

    If all of the situations for an extended entry are happy, the perform returns 2. For a brief entry, it returns 1. If neither set of situations is met, it returns 0, signaling no commerce.

    This logic interprets the visible sample into quantifiable guidelines, enabling its automated detection throughout backtesting. Subsequent, we’ll visualize the indicators on value chart and combine this logic right into a full buying and selling technique.

    def add_total_signal(df):
    df['TotalSignal'] = df.progress_apply(lambda row: total_signal(df, row.title), axis=1)
    return df

    def add_pointpos_column(df, signal_column):
    """
    Provides a 'pointpos' column to the DataFrame to point the place of assist and resistance factors.

    Parameters:
    df (DataFrame): DataFrame containing the inventory information with the desired SR column, 'Low', and 'Excessive' columns.
    sr_column (str): The title of the column to think about for the SR (assist/resistance) factors.

    Returns:
    DataFrame: The unique DataFrame with a further 'pointpos' column.
    """
    def pointpos(row):
    if row[signal_column] == 2:
    return row['Low'] - 1e-4
    elif row[signal_column] == 1:
    return row['High'] + 1e-4
    else:
    return np.nan

    df['pointpos'] = df.apply(lambda row: pointpos(row), axis=1)
    return df

    def plot_candlestick_with_signals(df, start_index, num_rows):
    """
    Plots a candlestick chart with sign factors.

    Parameters:
    df (DataFrame): DataFrame containing the inventory information with 'Open', 'Excessive', 'Low', 'Shut', and 'pointpos' columns.
    start_index (int): The beginning index for the subset of knowledge to plot.
    num_rows (int): The variety of rows of knowledge to plot.

    Returns:
    None
    """
    df_subset = df[start_index:start_index + num_rows]

    fig = make_subplots(rows=1, cols=1)

    fig.add_trace(go.Candlestick(x=df_subset.index,
    open=df_subset['Open'],
    excessive=df_subset['High'],
    low=df_subset['Low'],
    shut=df_subset['Close'],
    title='Candlesticks'),
    row=1, col=1)

    fig.add_trace(go.Scatter(x=df_subset.index, y=df_subset['pointpos'], mode="markers",
    marker=dict(dimension=10, colour="MediumPurple", image='circle'),
    title="Entry Factors"),
    row=1, col=1)

    fig.update_layout(
    width=1200,
    top=800,
    plot_bgcolor='black',
    paper_bgcolor='black',
    font=dict(colour='white'),
    xaxis=dict(showgrid=False, zeroline=False),
    yaxis=dict(showgrid=False, zeroline=False),
    showlegend=True,
    legend=dict(
    x=0.01,
    y=0.99,
    traceorder="regular",
    font=dict(
    household="sans-serif",
    dimension=12,
    colour="white"
    ),
    bgcolor="black",
    bordercolor="grey",
    borderwidth=2
    )
    )

    fig.present()

    After figuring out the candle patterns, the following step is to map them to the dataset and visualize the outcomes. This part introduces capabilities to use the sample logic, mark entry factors, and plot the indicators on a candlestick chart.

    Within the following picture we are able to see pattern of the info with the purple factors signaling a sample prevalence, if the purpose is beneath the candle it indicators a bullish sample and in the other way if the purpose is above the candle it indicators a bearish route.

    from backtesting import Technique
    from backtesting import Backtest

    def SIGNAL():
    return df.TotalSignal

    class MyStrat(Technique):
    mysize = 0.1 # Commerce dimension
    slperc = 0.04
    tpperc = 0.02

    def init(self):
    tremendous().init()
    self.signal1 = self.I(SIGNAL) # Assuming SIGNAL is a perform that returns indicators

    def subsequent(self):
    tremendous().subsequent()

    if self.signal1 == 2 and never self.place:
    # Open a brand new lengthy place with calculated SL and TP
    current_close = self.information.Shut[-1]
    sl = current_close - self.slperc * current_close # SL at 4% beneath the shut value
    tp = current_close + self.tpperc * current_close # TP at 2% above the shut value
    self.purchase(dimension=self.mysize, sl=sl, tp=tp)

    elif self.signal1 == 1 and never self.place:
    # Open a brand new quick place, setting SL based mostly on a strategy-specific requirement
    current_close = self.information.Shut[-1]
    sl = current_close + self.slperc * current_close # SL at 4% beneath the shut value
    tp = current_close - self.tpperc * current_close # TP at 2% above the shut value
    self.promote(dimension=self.mysize, sl=sl, tp=tp)

    Backtesting Framework

    1. Defining the Technique:
    • The MyStrat class inherits from the Technique module within the backtesting library:
    • Sign Integration: The SIGNAL perform provides the indicators generated earlier.
    • Place Administration: A brand new lengthy place is opened when the sign is 2 (lengthy entry), with cease loss (SL) and take revenue (TP) ranges dynamically calculated based mostly on percentages of the closing value.

    Loading a number of information information

    folder_path = "./data_forex"
    dataframes, file_names = read_data_folder(folder_path)

    for i, df in enumerate(dataframes):
    print("engaged on dataframe ", i, "...")
    df = add_total_signal(df)
    df = add_pointpos_column(df, "TotalSignal")
    dataframes[i] = df # Replace the dataframe within the record

    This code reads a folder of knowledge information and masses the info into a number of information frames.

    Backtest Execution

    outcomes = []
    heatmaps = []

    for df in dataframes:
    bt = Backtest(df, MyStrat, money=5000, margin=1/5, fee=0.0002)
    stats, heatmap = bt.optimize(slperc=[i/100 for i in range(1, 8)],
    tpperc=[i/100 for i in range(1, 8)],
    maximize='Return [%]', max_tries=3000,
    random_state=0,
    return_heatmap=True)
    outcomes.append(stats)
    heatmaps.append(heatmap)

    • Every dataframe is examined utilizing the Backtest module, initialized with $5,000 beginning money, a 20% margin, and a fee of 0.02%.
    • Parameters like slperc (cease loss) and tpperc (take revenue) are optimized utilizing a grid search to maximise returns.

    Aggregating Outcomes

    agg_returns = sum([r["Return [%]"] for r in outcomes])
    num_trades = sum([r["# Trades"] for r in outcomes])
    max_drawdown = min([r["Max. Drawdown [%]"] for r in outcomes])
    avg_drawdown = sum([r["Avg. Drawdown [%]"] for r in outcomes]) / len(outcomes)

    win_rate = sum([r["Win Rate [%]"] for r in outcomes]) / len(outcomes)
    best_trade = max([r["Best Trade [%]"] for r in outcomes])
    worst_trade = min([r["Worst Trade [%]"] for r in outcomes])
    avg_trade = sum([r["Avg. Trade [%]"] for r in outcomes]) / len(outcomes)

    print(f"Aggregated Returns: {agg_returns:.2f}%")
    print(f"Variety of Trades: {num_trades}")
    print(f"Most Drawdown: {max_drawdown:.2f}%")
    print(f"Common Drawdown: {avg_drawdown:.2f}%")
    print(f"Win Fee: {win_rate:.2f}%")
    print(f"Finest Commerce: {best_trade:.2f}%")
    print(f"Worst Commerce: {worst_trade:.2f}%")
    print(f"Common Commerce: {avg_trade:.2f}%")

    Outcomes throughout all dataframes are aggregated to calculate key metrics:

    • Aggregated Returns: Whole proportion return throughout all datasets.
    • Variety of Trades: Whole variety of trades executed.
    • Most and Common Drawdown: The deepest and common dips within the account stability.
    • Win Fee: Proportion of trades that ended profitably.
    • Finest and Worst Commerce: The best and lowest returns from particular person trades.
    • Common Commerce Efficiency: Common return per commerce.

    Plotting The Fairness Curves

    equity_curves = [stats['_equity_curve']['Equity'] for stats in outcomes]
    max_length = max(len(fairness) for fairness in equity_curves)

    # Pad every fairness curve with the final worth to match the utmost size
    padded_equity_curves = []
    for fairness in equity_curves:
    last_value = fairness.iloc[-1]
    padding = [last_value] * (max_length - len(fairness))
    padded_equity = fairness.tolist() + padding
    padded_equity_curves.append(padded_equity)

    equity_df = pd.DataFrame(padded_equity_curves).T

    import matplotlib.pyplot as plt

    equity_df.plot(form='line', figsize=(10, 6), legend=True).set_facecolor('black')
    plt.gca().spines['bottom'].set_color('black')
    plt.gca().spines['left'].set_color('black')
    plt.gca().tick_params(axis='x', colours='black')
    plt.gca().tick_params(axis='y', colours='black')
    plt.gca().set_facecolor('black')
    plt.legend(file_names)

    We will see that the sample reults are optimistic on some property and never very promising on others. The problem right here is that I examined this technique on Foreign exchange information however Michael Harris described it in his guide for shares information, this could be affecting the outcomes as properly. Nonetheless I strongly consider that if we establish 5 patterns as this one and we run these concurrently on let’s say 10 completely different property, this could be an excellent starter for a buying and selling system, that may be simply automated not less than signaling potential trades and sending alerts to the human dealer. Clearly the system is just not totally automated as a result of a dealer nonetheless must confirm the validity of the sign, however the algorithm is doing the ready time and probing the market on behalf of the dealer… which is extra snug than buying and selling in full guide mode.



    Supply hyperlink

    Share. Facebook Twitter Pinterest LinkedIn Tumblr Email

    Related Posts

    JPMorgan bridges blockchain and conventional finance in landmark pilot transaction

    May 15, 2025

    LangChain's Interrupt 2025: A New Period for AI Brokers

    May 15, 2025

    Synthetix acquires Derive with a $27 million token swap

    May 15, 2025

    BitMEX Introduces LAUNCHCOINUSDT Perpetual Swap with 12.5x Leverage

    May 15, 2025
    Latest Posts

    President Trump Will Print Enough Money To Pump Bitcoin to $1,000,000 by 2028: Arthur Hayes – The Daily Hodl

    May 15, 2025

    Majority Of UK Bitcoin Customers Have By no means Offered, CoinCorner Report Reveals

    May 15, 2025

    เจาะลึก: เหรียญคริปโตน่าลงทุน BTC Bull Token ที่ ChatGPT แนะนำปี 2025 | Bitcoinist.com

    May 15, 2025

    NFT founder stole hundreds of thousands from Bitcoin challenge, traders allege

    May 15, 2025

    Abraxas Capital Bets $561 Million on ETH, Ditches Bitcoin in Strategic Energy Transfer

    May 15, 2025

    Peter Schiff Admits “Actual Use Case” for Bitcoin – Hedging Towards MicroStrategy – BlockNews

    May 15, 2025

    Bitcoin Tops $104K as International Market Momentum Outpaces Korean Demand

    May 15, 2025

    Bitcoin Is King, However Don’t Ignore the Others: Bitwise CIO Counsel Diversified Crypto Publicity

    May 15, 2025

    CryptoVideos.net is your premier destination for all things cryptocurrency. Our platform provides the latest updates in crypto news, expert price analysis, and valuable insights from top crypto influencers to keep you informed and ahead in the fast-paced world of digital assets. Whether you’re an experienced trader, investor, or just starting in the crypto space, our comprehensive collection of videos and articles covers trending topics, market forecasts, blockchain technology, and more. We aim to simplify complex market movements and provide a trustworthy, user-friendly resource for anyone looking to deepen their understanding of the crypto industry. Stay tuned to CryptoVideos.net to make informed decisions and keep up with emerging trends in the world of cryptocurrency.

    Top Insights

    NFT Market OpenSea Provides Help For Ronin Community

    March 26, 2025

    Crypto Analyst Predicts Incoming Bitcoin Parabolic Rally, Says BTC at Level The place Issues Get Thrilling – The Day by day Hodl

    December 22, 2024

    Finest Crypto to Purchase to Purchase as MicroStrategy Plans to Add $21B $BTC

    March 11, 2025

    Subscribe to Updates

    Get the latest creative news from FooBar about art, design and business.

    • Home
    • Privacy Policy
    • Contact us
    © 2025 CryptoVideos. Designed by MAXBIT.

    Type above and press Enter to search. Press Esc to cancel.