Creating Trading Rules With Intermarket Relationships

Discussion in 'Strategy Building' started by ph1l, Aug 3, 2023.

  1. ph1l

    ph1l

    In this example, I create trading rules by comparing values from fitted price curves.

    Software finds three swings in price data as above.

    The software creates curves to fit the price swings that sum a least squares regression line with zero or more cosine waves using the Goertzel algorithm.

    To help curve values be comparable to curve values from different times, the software standardizes them by removing:
    • the y intercept from the least squares regression line
    • the estimated standard deviation of the price data from the least squares regression line
    • the estimated standard deviation of the differences if price values to the least squares regression line

    For example, using open prices of QQQ for 37 trading days from 20170615 to 20170807, the fitted curve found before the above removals is
    Code:
    QQQ_20170807_37_opy = 137.947982788086 + 3.77645492553711 * -0.0476661579206547 * x  +  1.5986567735672 * (
        0.541859686374664 * cos(twopi / 22.9808105990718 * x  +   3.64079618453979)
        + 0.210554629564285 * cos(twopi / 13.5704574901945 * x  +   5.54141235351562)
        + 0.13944485783577 * cos(twopi / 106.626021858345 * x  +   1.72074127197266)
        + 0.0950047299265862 * cos(twopi / 2.38496891108685 * x  +   6.05813837051392)
        + 0.0915462970733643 * cos(twopi / 5.50749497583084 * x  +   4.27757024765015) ) ;
    
    And for 48 trading days from 20231002 to 20231208, the fitted curve found before removals is
    Code:
    QQQ_20231208_48_opy = 389.808898925781 + 20.9928169250488 * -0.0383396329932307 * x  +  7.348717212677 * (
        0.502204477787018 * cos(twopi / 30.906657620687 * x  +   3.87648510932922)
        + 0.194004282355309 * cos(twopi / 17.810513676591 * x  +   5.62850379943848)
        + 0.111993163824081 * cos(twopi / 8.01638992087503 * x  +   0.216300472617149)
        + 0.0793934985995293 * cos(twopi / 12.8295016279416 * x  +   0.930293023586273)
        + 0.0728166997432709 * cos(twopi / 4.91025367585738 * x  +   4.41841173171997) ) ;
    
    The curves point backwards in time, so x=0 refers to the current bar, x=1 is for the previous bar, etc.

    Graphs of these show similar structures
    upload_2024-2-2_21-43-37.png upload_2024-2-2_21-44-33.png

    But the values of the curves are very different and not very comparable.

    After the removals, the curve formulas are
    Code:
    QQQ_20170807_37_opy = -0.0476661579206547 * x  +  (
        0.541859686374664 * cos(twopi / 22.9808105990718 * x  +   3.64079618453979)
        + 0.210554629564285 * cos(twopi / 13.5704574901945 * x  +   5.54141235351562)
        + 0.13944485783577 * cos(twopi / 106.626021858345 * x  +   1.72074127197266)
        + 0.0950047299265862 * cos(twopi / 2.38496891108685 * x  +   6.05813837051392)
        + 0.0915462970733643 * cos(twopi / 5.50749497583084 * x  +   4.27757024765015) ) ;
    
    QQQ_20231208_48_opy = -0.0383396329932307 * x  +  (
        0.502204477787018 * cos(twopi / 30.906657620687 * x  +   3.87648510932922)
        + 0.194004282355309 * cos(twopi / 17.810513676591 * x  +   5.62850379943848)
        + 0.111993163824081 * cos(twopi / 8.01638992087503 * x  +   0.216300472617149)
        + 0.0793934985995293 * cos(twopi / 12.8295016279416 * x  +   0.930293023586273)
        + 0.0728166997432709 * cos(twopi / 4.91025367585738 * x  +   4.41841173171997) ) ;
    
    Now the curves have comparable values.
    upload_2024-2-2_21-47-4.png upload_2024-2-2_21-47-25.png

    The functions for the curves run on multiple ETFs to create values five trading days before the current bar through five trading days after the current bar.

    Input price data uses values adjusted for splits and dividends on assorted ETFs in the attached tab-separated etf_inputs.csv

    Training data was for simulated trades entered from 2001-03-30 through 2017-03-22.
    Evaluation data was for simulated trades entered from 2017-03-23 through 2024-01-25.
    The simulated trades entered long at the open and exited at the next trading day's open.
    The simulated trades did not account for slippage and commission.

    A genetic program rules generator created rules such as for QQQ:
    Code:
    if  IOOop_AfterStdz2 >= IOOop_AfterStdz3    if  IOOop_BeforeStdz0 > IOOop_AfterStdz4    if  IOOop_AfterStdz4 < IOOop_BeforeStdz1    if  IOOop_AfterStdz1 > IOOop_AfterStdz3    if  IOOop_BeforeStdz5 >= IOOop_BeforeStdz3    return  1
    
    if  IOOop_BeforeStdz0 > IOOop_AfterStdz4    if  IOOop_BeforeStdz0 >= IOOop_AfterStdz4    if  IOOop_BeforeStdz5 >= IOOop_BeforeStdz3    if  IOOop_BeforeStdz0 > IOOop_BeforeStdz1    return  1
    
    if  EWYop_BeforeStdz4 >= EWYop_BeforeStdz3    if  EWYop_AfterStdz2 > -0.124356    if  EWYop_AfterStdz1 >= -0.598665    if  EWYop_BeforeStdz4 < EWYop_AfterStdz3    return  1
    
    if  EWYop_BeforeStdz3 <= 0.728926    if  EWYop_BeforeStdz3 <= -0.330632    if  EWYop_BeforeStdz4 < 1.59147    if  EWYop_AfterStdz1 >= -0.728304    if  EWYop_AfterStdz2 <= 0.301724    if  EWYop_BeforeStdz0 >= EWYop_BeforeStdz1    return  1
    
    if  IWNop_BeforeStdz1 >= -1.28908    if  IWNop_BeforeStdz3 >= IWNop_AfterStdz4    if  IWNop_AfterStdz2 <= IWNop_BeforeStdz4    if  IWNop_BeforeStdz1 > 0.563882    return  1
    
    if  IWNop_BeforeStdz4 >= IWNop_AfterStdz3    if  IWNop_AfterStdz1 < IWNop_BeforeStdz0    if  IWNop_BeforeStdz1 > IWNop_AfterStdz4    if  IWNop_AfterStdz3 < IWNop_AfterStdz1    if  IWNop_BeforeStdz4 > 0.357067    return  1
    
    if  XLEop_BeforeStdz2 <= XLEop_BeforeStdz0    if  XLEop_BeforeStdz2 < XLEop_BeforeStdz0    if  XLEop_BeforeStdz1 < 0.658045    if  XLEop_AfterStdz2 >= XLEop_AfterStdz4    if  XLEop_AfterStdz4 < 0.123062    return  1
    
    if  EWYop_AfterStdz2 < 0.293288    if  EWYop_AfterStdz1 >= EWYop_BeforeStdz2    if  EWYop_BeforeStdz5 <= EWYop_AfterStdz2    if  EWYop_BeforeStdz1 < EWYop_BeforeStdz0    if  EWYop_AfterStdz1 > EWYop_BeforeStdz5    return  1
    
    if  XLEop_BeforeStdz1 > XLEop_BeforeStdz3    if  XLEop_AfterStdz1 >= -0.429701    if  XLEop_BeforeStdz2 <= XLEop_AfterStdz2    if  XLEop_AfterStdz4 < 0.237824    if  XLEop_BeforeStdz2 <= XLEop_AfterStdz2    return  1
    
    For the evaluation period, simulated buy and hold performance was
    total return 241.72%, compound annual return 19.66%, maximum drawdown 35.12%, daily mean result 0.0714%, daily mean win 0.9900%, daily mean loss 1.1012%, number of trading days 1722, number of daily wins 970, daily win rate 56.33%

    The simulated performance using the rules for the evaluation period was
    total return 254.12%, compound annual return 20.28%, maximum drawdown 21.32%, mean result 0.1365%, mean win 1.0127%, mean loss 0.9623%, number of trades 927, number of wins 518, win rate 55.88%
     
    #11     Feb 2, 2024