Creating Trading Rules With Intermarket Relationships

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

  1. ph1l

    ph1l

    Here is an example of rules created through genetic programming to simulate trades in one asset with data from other assets.

    This example uses daily close values to simulate trades entering long at the next trading day's close value of NASDAQ 100 with and exiting at the close the next trading day.

    The inputs are close values for the current trading day (suffix raw000), and close values for the previous 21 trading days (suffixes raw001 through raw021) downloaded from Yahoo finance for the following:
    • irxrawNNN -- 13 Week Treasury Bill (^IRX)
    • fvxrawNNN -- Treasury Yield 5 Years (^FVX)
    • tnxrawNNN -- Treasury Yield 10 Years (^TNX)
    • tyxrawNNN -- Treasury Yield 30 Years (^TYX)
    • aordrawNNN -- ALL ORDINARIES (^AORD)
    • asx200rawNNN -- S&P/ASX 200 (^AXJO)
    • jkserawNNN -- IDX COMPOSITE (^JKSE)
    • hsirawNNN -- HANG SENG INDEX (^HSI)
    • vixrawNNN -- CBOE Volatility Index (^VIX)

    The software supports the interest rates, equities, and volatility as separate types as in this post, and operations between different types result in undef values which evaluate false in the if statements.

    In the following generated pseudocode rules, "return 1" means the trade would be entered on the close of the next trading day. Each block ending with a "return 1" is an individual rule from a separate run of the rule generating software.
    Code:
    # types_for_runtime_checking ^(?:vix)raw\d ^(?:fvx|irx|tnx|tyx)raw\d ^(?:aord|asx200|bfx|bvsp|cac40|dji|djt|dju|gdaxi|gspc|gsptse|hsi|ixic|jkse|mid|mxx|n225|nd100|ndbank|ndfin|ndind|ndinsr|ndtran|nya|rua|rui|rut|sp100|sp600|spcd|spcst|spenrg|spfin|sphe|spind|spmat|sptech|sptel|sput|ta125|uty|w5000|xau|xoi)raw\d
    
    R0 = R1 = undef
    R1  = 0.967139 * aordraw013
    if  aordraw004 >= R1    R1  = 0.873757 * tyxraw013
    R0  = 0.967687 * tnxraw005
    if  R1 > irxraw002    if  R1 < R0    if  R0 <= tnxraw000    if  tyxraw019 >= R0    R0  = 0.925426 * tyxraw002
    if  fvxraw010 > R0    if  tnxraw018 >= R0    if  irxraw017 <= R1    return  1
    
    R1 = R0 = undef
    R0  = 0.874442 * vixraw018
    if  R0 > vixraw007    R0  = 0.872526 * vixraw021
    if  R0 <= vixraw005    if  vixraw000 >= R0    R0  = 0.924405 * vixraw015
    R1  = 0.930402 * vixraw018
    if  R0 <= vixraw018    R1  = 0.936894 * vixraw011
    if  R1 < vixraw016    if  vixraw010 <= R0    if  vixraw008 < R0    return  1
    
    R0 = R1 = undef
    R0  = 0.836893 * irxraw016
    if  R0 < irxraw013    R1  = 0.105203 * fvxraw019
    R0  = 0.978807 * irxraw021
    if  irxraw010 < R0    R0  = 0.724784 * irxraw015
    if  irxraw017 <= R0    R0  = 0.851472 * irxraw020
    if  R1 > irxraw002    R1  = 0.946637 * asx200raw015
    if  asx200raw000 > R1    if  R0 < irxraw013    if  asx200raw008 >= R1    if  asx200raw017 >= R1    return  1
    
    R0 = R1 = undef
    R1  = 0.133722 * fvxraw011
    R0  = 0.123306 * fvxraw017
    if  R1 >= R0    R1  = 0.983625 * asx200raw003
    if  R1 < asx200raw008    R1  = 0.0825821 * fvxraw000
    R0  = 0.703178 * irxraw018
    if  R1 >= irxraw021    if  irxraw010 > R0    R0  = 0.123306 * fvxraw017
    if  R0 >= R1    if  irxraw010 > R0    R0  = 0.123306 * fvxraw017
    if  irxraw010 > R0    if  irxraw009 < R0    R0  = 0.123306 * fvxraw017
    if  R0 > irxraw012    if  irxraw015 < R0    return  1
    
    R0 = R1 = undef
    R1  = 0.934906 * asx200raw018
    R0  = 0.979026 * jkseraw000
    if  jkseraw019 >= R0    R0  = 0.518442 * asx200raw003
    if  jkseraw015 >= R0    if  R1 < asx200raw001    if  R1 < asx200raw009    R0  = 0.953588 * jkseraw001
    if  jkseraw010 <= R0    if  R1 > asx200raw004    R1  = 0.975936 * jkseraw010
    if  R1 > jkseraw008    if  R1 <= asx200raw009    if  jkseraw021 >= R0    if  R1 <= asx200raw007    return  1
    
    R0 = R1 = undef
    R1  = 0.993643 * asx200raw002
    if  aordraw013 >= R1    if  asx200raw010 <= R1    R1  = 0.968812 * asx200raw003
    if  aordraw014 < R1    R1  = 0.965842 * aordraw009
    if  asx200raw020 <= R1    if  aordraw004 > R1    R0  = 0.999385 * asx200raw021
    if  aordraw018 >= R0    R0  = 0.983193 * asx200raw018
    R1  = 0.968812 * asx200raw003
    if  R1 > asx200raw021    if  R1 >= R0    R1  = 0.967574 * aordraw001
    if  R0 <= asx200raw019    if  asx200raw002 > R1    if  R0 < asx200raw005    if  aordraw000 > R1    return  1
    
    R1 = R0 = undef
    R0  = 0.970766 * aordraw007
    if  aordraw015 > R0    R0  = 0.996531 * asx200raw011
    if  R0 > asx200raw012    R1  = 0.995876 * asx200raw011
    R0  = 0.993601 * asx200raw014
    if  R1 < aordraw004    if  R1 > R0    if  aordraw016 >= R0    if  R1 <= aordraw003    return  1
    
    The training data had 5310 simulated trades starting 1993-06-04 through 2014-07-03.

    The out-of-sample evaluation data had 2275 simulated trades starting 2014-07-07 through 2023-07-28 with
    total return 260.67% (not including dividends or trading costs); compound annual return 15.20%; mean return 0.0564%; median return 0.1121%; winning percent 55.47

    The evaluation period with the generated rules applied had 1676 simulated, one-trading-day trades (73.67% of the total evaluation trading days) with
    total return 643.1014% (not including dividends or trading costs); compound annual return 24.76%; mean return 0.1197%; median return 0.1554%; winning percent 57.88

    If trades on consecutive trading days were combined (total return unchanged), there would have been 227 trades with
    mean return 0.8874%; median return 0.7334%; winning percent 69.16
    The combined trades would have lasted from 1 to 89 trading days with a mean 7.38 trading days and a median 3 trading days.

    Each individual rule had better performance per trade on the out-of-sample data than the equivalent buy-and-hold trades. I think there is a reasonable chance the rules would have better performance than buy-and-hold trades in the future.

    Comments?
     
    murray t turtle likes this.
  2. TrAndy2022

    TrAndy2022

    Which software did you use for the genetic programming approach ? What (and how many different) kind of data did you use for intermarket relationships ? What was your fitness function ? If you used daily data only did you make sure that the close prices are on the same exact time ending on each of your different data sets to prevent data snooping bias ?
     
  3. ph1l

    ph1l

    I wrote the software in C++ and opencl with perl and shell controlling it. It uses linear genetic programming mostly based on the ideas from this book



    The inputs are daily close prices for the current trading day and the previous 21 trading days for the assets I wrote in the post above. This data for this example has three types: U.S. Treasury interest rates, Australian and Asian equity indexes, and the VIX. The target the software is measuring against is the NASDAQ 100 which was not one of the inputs.

    For each run of the software, I used various combinations of the inputs; i.e., not all of them.

    The rules were allowed to use two registers to store intermediate values, and the operators allowed for these runs were if statement comparisons (< <= > >=) and multiplication of an input by a constant. The if statements have the next statement as the "then" part and no "else" part.

    A register assigned a value assumes the type of the expression it was assigned to. If an if statement tries to compare two operands with different types, the comparison is always interpreted as false. For example, in this rule
    Code:
    R0 = R1 = undef
    R1  = 0.967139 * aordraw013
    if  aordraw004 >= R1    R1  = 0.873757 * tyxraw013
    R0  = 0.967687 * tnxraw005
    if  R1 > irxraw002    if  R1 < R0    if  R0 <= tnxraw000    if  tyxraw019 >= R0    R0  = 0.925426 * tyxraw002
    if  fvxraw010 > R0    if  tnxraw018 >= R0    if  irxraw017 <= R1    return  1
    
    When the "if R1 > irxraw002" executes, R1 could be an equity type (from "R1 = 0.967139 * aordraw013") or an interest rate type (from "R1 = 0.873757 * tyxraw013). if R1 has the equity type, the if R1 > irxraw002 would not evaluate true because it's being compared to an interest rate type.

    The fitness function is a variation of the Ulcer Performance Index multiplied by the proportion of hits (number of inputs a rule passes on divided by total number of inputs) and includes a penalty if there were too many hits. The penalty helps avoid the software thinking the fittest rule is one that takes every simulated trade.

    The timestamps of the data is whatever Yahoo Finance said what the closing price was for a particular day. For example, today is August 3, and the closing price for NASDAQ 100 is available for August 2 and before. One of the inputs is ASX 200, and Australian markets have already closed for August 3. The software will not use the data for ASX 200 for August 3 and would only use the data for ASX 200 for August 2 and before. This avoids data snooping.

    If the data for August 2 and before was used as training data, the inputs for the history would have ended July 31, and the simulated trade would have been entered long at the close of August 1 and exited at the close of August 2.

    If an exchange for one of the inputs was closed on a day U.S. equity markets are open, the previous close price for that input gets carried forward.
     
  4. TrAndy2022

    TrAndy2022

    Did you check walk forward optimizing as rolling window because then you estimate better the predictive value in your insample analysis. Actually you have only one large out-of-sample test period. That is not enough to make judgement I would say. Check rolling WF analysis and optimize the IS to OOS window. Then come back with your results and let's see.
     
    ph1l and murray t turtle like this.
  5. %%
    I dont think that will help very much;
    2 day trades on QQQ, even if its profitable in a bull market + most likely it IS profitable,+ in future .
    MOST likely did include enough of a bull-bear cycle, to be oK,qqq.
    I have traded QQQ 2 days before so I'm not saying its bad.....................
    Yes i think it would outperform QQQ or QLD[3.8% t bills in it]buy + hold in a bear trend ;
    but not a bull trend which we are in[2oo day moving average signal]:caution::caution:.
    Thanks
     
    ph1l likes this.
  6. ph1l

    ph1l

    I looked at walk-forward optimization with a rolling window.
    https://ungeracademy.com/posts/how-to-use-walk-forward-analysis-you-may-be-doing-it-wrong
    And, I found a 2020 paper (attached) describing the authors' use of genetic programming with walk-forward optimization.
    upload_2023-8-5_8-36-53.png
    They combined some operators and technical indicators
    upload_2023-8-5_8-39-1.png

    on individual stocks
    upload_2023-8-5_8-39-56.png

    with a few fixed parameters
    upload_2023-8-5_8-40-29.png

    They don't say what they would do after walk-forward optimization is done, but
    I would not use rules from an untested retraining until they pass some forward testing.

    When I use my rule generator on training data, if the best rule does poorly on evaluation data, I don't use the rule. So the evaluation data is also used during training -- just not to create the rules.

    I try to avoid overfitting by
    • limiting the maximum number of statements in a rule
    • allowing crossover and mutation to increase and/or decrease the number of statements in a rule (avoids having all rules use the maximum number of statements)
    • penalizing rules that hit too many of the inputs (avoids having a rule hit all inputs and being equivalent to buy-and-hold)
    • limiting the operators a rule can use (e.g., only multiplication and comparisons)
    • limiting the class of operands a rule can use (e.g., multiplication must have a constant and an input)
    • limiting the inputs for a training run (e.g., allowing 13 Week Treasury Bill and Treasury Yield 5 Years but not Treasury Yield 30 Years)
    • avoiding individual statements using two operands of different types (e.g., comparing an interest rate and an equity is always false)
    • sometimes randomly picking a fraction of the input data
    • limiting the number of generations for a run
    I change settings from one run to another to see which ones tend to produce rules that work well on the evaluation data.

    If I did walk-forward optimization, each moving window would have very different rules. It might show that with appropriate training and evaluation windows, the methodology I'm using can be successful in the future. But I can already tell that from the larger training and evaluation window I used. So, I don't think walk forward evaluation would be that valuable for this type of rule generation. And, all other things equal, using shorter training windows makes overfitting more likely.

    Here is someone else's opinion on walk-forward optimization.

     
  7. ph1l

    ph1l

    Here is another example of rules created through genetic programming to simulate trades in one asset with data from other assets.

    This example uses daily close values to simulate trades entering long at the next trading day's close value of Russell 2000 and exiting at the close the next trading day.

    The inputs are close values for the current trading day (suffix raw000), and close values for the previous 21 trading days (suffixes raw001 through raw021) downloaded from Yahoo finance for the following:
    • ta125rawNNN -- TA-125 (^TA125.TA)
    • spenrgrawNNN -- S&P 500 Energy (Sector) (^GSPE)
    • bvsprawNNN -- IBOVESPA (^BVSP)
    • asx200rawNNN -- S&P/ASX 200 (^AXJO)
    • aordrawNNN -- ALL ORDINARIES (^AORD)
    • irxrawNNN -- 13 Week Treasury Bill (^IRX)
    • tnxrawNNN -- Treasury Yield 10 Years (^TNX)
    • vixrawNNN -- CBOE Volatility Index (^VIX)

    The software supports the interest rates, equities, and volatility as separate types as before, and operations between different types result in undef values which evaluate false in the if statements.

    In the following generated pseudocode rules, "return 1" means the trade would be entered on the close of the next trading day. Each block ending with a "return 1" is an individual rule from a separate run of the rule generating software.
    Code:
    # types_for_runtime_checking ^(?:vix)raw\d ^(?:fvx|irx|tnx|tyx)raw\d ^(?:aord|asx200|bfx|bvsp|cac40|dji|djt|dju|gdaxi|gspc|gsptse|hsi|ixic|jkse|mid|mxx|n225|nd100|ndbank|ndfin|ndind|ndinsr|ndtran|nya|rua|rui|rut|sp100|sp600|spcd|spcst|spenrg|spfin|sphe|spind|spmat|sptech|sptel|sput|ta125|uty|w5000|xau|xoi)raw\d
    
    R1 = R0 = undef
    R0  = 0.216482 * ta125raw006
    R1  = 0.955771 * ta125raw019
    if  R1 <= ta125raw005    R0  = 0.985709 * ta125raw009
    if  ta125raw005 >= R0    R1  = 0.991367 * ta125raw009
    if  ta125raw014 < R1    if  ta125raw011 < R1    if  ta125raw014 < R1    return  1
    
    R0 = R1 = undef
    R0  = 0.97479 * spenrgraw010
    if  R0 <= spenrgraw009    R0  = 0.982745 * spenrgraw012
    R1  = 0.99942 * spenrgraw000
    if  R1 <= spenrgraw006    R0  = 0.970778 * spenrgraw006
    if  R0 >= spenrgraw017    if  R0 >= R1    R0  = 0.970778 * spenrgraw006
    if  R0 > spenrgraw018    if  R0 <= R1    if  spenrgraw017 <= R0    return  1
    
    R1 = R0 = undef
    R1  = 0.958637 * bvspraw013
    R0  = 0.954164 * bvspraw006
    if  bvspraw013 > R0    if  R0 <= bvspraw016    if  R0 <= bvspraw016    if  R1 <= R0    if  R0 < bvspraw012    if  bvspraw015 > R0    return  1
    
    R1 = R0 = undef
    if  asx200raw018 >= R1    R1  = 0.701134 * asx200raw016
    R0  = 0.993568 * asx200raw001
    if  R0 <= asx200raw004    R1  = 0.984193 * asx200raw012
    if  R1 <= asx200raw004    if  R1 > R0    R1  = 0.984009 * asx200raw013
    if  R1 >= asx200raw020    return  1
    
    R1 = R0 = undef
    R0  = 0.987216 * aordraw004
    if  aordraw014 < R0    R1  = 0.989049 * aordraw021
    if  aordraw019 >= R1    if  aordraw013 >= R1    if  R0 > aordraw019    if  R0 < aordraw006    if  R0 < aordraw004    if  aordraw003 > R0    if  R1 < aordraw014    return  1
    
    R1 = R0 = undef
    R1  = 0.987059 * tnxraw020
    R0  = 0.988015 * tnxraw003
    if  R0 < tnxraw013    if  R1 >= tnxraw016    if  R1 >= tnxraw016    return  1
    
    R1 = undef
    R1  = 0.954557 * vixraw018
    if  vixraw001 < R1    R1  = 0.986823 * vixraw002
    if  R1 < vixraw016    if  vixraw002 <= R1    R1  = 0.536007 * irxraw004
    if  R1 > vixraw008    if  vixraw008 < R1    return  1
    
    R0 = R1 = undef
    R0  = 0.964751 * vixraw008
    R1  = 0.996452 * vixraw008
    if  vixraw018 > R1    R0  = 0.81551 * vixraw004
    if  vixraw016 >= R0    if  R0 <= R1    R0  = 0.841603 * vixraw011
    R1  = 0.787182 * vixraw020
    if  R1 > R0    if  R1 < vixraw002    if  R0 < R1    return  1
    
    R0 = R1 = undef
    R1  = 0.796143 * irxraw010
    if  R1 <= irxraw017    R0  = 0.823123 * irxraw004
    if  irxraw012 >= R0    R0  = 0.823123 * irxraw004
    R1  = 0.735272 * irxraw021
    if  irxraw012 >= R0    R1  = 0.90368 * vixraw017
    if  vixraw010 <= R1    R0  = 0.823123 * irxraw004
    if  R0 <= irxraw004    R0  = 0.938806 * irxraw018
    R1  = 0.90368 * vixraw017
    if  vixraw010 <= R1    if  irxraw012 >= R0    return  1
    
    
    The training data had 5310 simulated trades starting 1993-06-04 through 2014-07-03.

    The out-of-sample evaluation data had 2275 simulated trades starting 2014-07-07 through 2023-07-28 with
    total return 48.42% (not including dividends or trading costs); compound annual return 4.45%; mean return 0.01736%; median return 0.07983%; winning percent 52.88

    The evaluation period with the generated rules applied had 1819 simulated, one-trading-day trades (79.96% of the total evaluation trading days) with
    total return 271.97% (not including dividends or trading costs); compound annual return 15.59%; mean return 0.0722%; median return 0.1226%; winning percent 54.54

    If trades on consecutive trading days were combined (total return unchanged), there would have been 218 trades with
    mean return 0.6044%; median return 0.2834%; winning percent 56.88
    The combined trades would have lasted from 1 to 47 trading days with a mean 8.34 trading days and a median 5 trading days.

    Each individual rule had better performance per trade on the out-of-sample data than the equivalent buy-and-hold trades. I think there is a reasonable chance the rules would have better performance than buy-and-hold trades in the future.
     
    Last edited: Aug 10, 2023
  8. ph1l

    ph1l

    Here is another example of rules created through genetic programming to simulate trades in one asset with data from other assets (also the same asset).

    This example uses daily close values to simulate trades entering long at the next trading day's close value of IBOVESPA and exiting at the close the next trading day.

    The inputs are close values for the current trading day (suffix raw000), and close values for the previous 21 trading days (suffixes raw001 through raw021) downloaded from Yahoo finance for the following:
    • aordrawNNN -- ALL ORDINARIES (^AORD)
    • bvsprawNNN -- IBOVESPA (^BVSP)
    • djurawNNN -- Dow Jones Utility Average (^DJU)
    • fvxrawNNN -- Treasury Yield 5 Years (^FVX)
    • gdaxirawNNN -- DAX PERFORMANCE-INDEX (^GDAXI)
    • nd100rawNNN -- NASDAQ 100 (^NDX)
    • ruirawNNN -- Russell 1000 (^RUI)
    • spcdrawNNN -- S&P 500 Consumer Discretionary (Sector) (^SP500-25)
    • spherawNNN -- S&P 500 Health Care (Sector) (^SP500-35)
    • spindrawNNN -- S&P 500 Industrials (Sector) (^SP500-20)

    Unlike the earlier rules, run-time typing does not apply because each group of rules from a run has only one type of input. However, if a register (R0 or R1) has an undef value, any comparison with the register would evaluate false.

    In the following generated pseudocode rules, "return 1" means the trade would be entered on the close of the next trading day. Each block ending with a "return 1" is an individual rule from a separate run of the rule generating software.
    Code:
    R0 = R1 = undef
    R1  = 0.959715 * spindraw001
    if  R1 < spindraw017    R1  = 0.988802 * spindraw005
    if  R1 <= R0    if  R1 <= spindraw017    if  R1 >= R0    if  R1 < spindraw017    R1  = 0.988802 * spindraw005
    if  R1 >= spindraw009    if  spindraw007 >= R1    return  1
    
    R0 = R1 = undef
    R1  = 0.990977 * spheraw006
    R0  = 0.991473 * spheraw011
    if  R0 > spheraw013    if  R0 <= spheraw005    if  spheraw013 > R1    if  R0 > spheraw013    R0  = 0.965347 * spheraw008
    if  R1 >= spheraw001    if  R1 > spheraw011    if  R0 < spheraw018    if  R0 > spheraw021    R1  = 0.992782 * spheraw004
    if  R1 < spheraw001    R0  = 0.965347 * spheraw008
    if  spheraw000 <= R1    if  spheraw015 >= R0    if  R1 < spheraw005    return  1
    
    R0 = R1 = undef
    R0  = 0.97702 * spcdraw003
    R1  = 0.983339 * spcdraw011
    if  spcdraw006 >= R0    if  R1 < spcdraw009    R0  = 0.988494 * spcdraw001
    R1  = 0.983339 * spcdraw011
    if  spcdraw000 > R1    if  spcdraw004 >= R1    if  spcdraw018 >= R0    if  R1 < R0    if  spcdraw014 >= R1    if  spcdraw007 >= R1    return  1
    
    R1 = R0 = undef
    R1  = 0.987758 * ruiraw001
    R0  = 0.980145 * ruiraw012
    if  R1 > R0    if  R1 < ruiraw008    if  R1 < ruiraw017    if  R1 < ruiraw008    if  R1 < ruiraw004    if  R1 < ruiraw017    if  R1 < ruiraw017    if  R1 < ruiraw008    return  1
    
    R0 = R1 = undef
    R1  = 0.971681 * nd100raw000
    if  nd100raw008 >= R1    if  R1 > nd100raw012    R0  = 0.824234 * nd100raw008
    R1  = 0.995088 * nd100raw003
    if  R1 >= nd100raw000    R0  = 0.960204 * nd100raw009
    R1  = 0.982535 * nd100raw016
    if  R1 < nd100raw014    if  R1 < nd100raw004    if  nd100raw001 >= R1    if  nd100raw017 >= R1    if  R1 >= R0    if  R1 > R0    if  R0 <= nd100raw013    if  nd100raw015 > R0    if  nd100raw009 > R0    return  1
    
    R1 = R0 = undef
    R0  = 0.991523 * aordraw004
    R1  = 0.995105 * aordraw010
    if  R1 < aordraw007    if  R1 < aordraw007    if  aordraw006 <= R0    return  1
    
    R0 = R1 = undef
    R0  = 0.975845 * gdaxiraw005
    if  R0 <= gdaxiraw011    if  gdaxiraw013 <= R0    R1  = 0.555409 * gdaxiraw001
    if  gdaxiraw012 >= R1    R0  = 0.987969 * gdaxiraw010
    if  R0 >= gdaxiraw020    if  gdaxiraw017 >= R1    if  gdaxiraw006 >= R1    R0  = 0.987969 * gdaxiraw010
    if  R0 < gdaxiraw017    if  R0 >= gdaxiraw020    R1  = 0.263305 * gdaxiraw020
    if  R1 < gdaxiraw011    R1  = 0.934423 * gdaxiraw006
    if  gdaxiraw017 >= R1    if  gdaxiraw020 <= R0    return  1
    
    R1 = R0 = undef
    R1  = 0.947201 * fvxraw005
    R0  = 0.981228 * fvxraw012
    if  R0 >= fvxraw018    if  fvxraw006 >= R0    R0  = 0.637228 * fvxraw014
    if  R1 >= R0    if  R1 >= R0    if  R0 <= R1    if  fvxraw004 > R0    if  fvxraw007 >= R1    if  R0 < fvxraw015    if  fvxraw010 >= R0    if  fvxraw015 > R1    if  R0 <= R1    if  R1 < fvxraw013    if  fvxraw015 > R1    if  fvxraw015 >= R0    return  1
    
    R1 = R0 = undef
    R1  = 0.997754 * djuraw010
    if  djuraw014 >= R1    R1  = 0.647859 * djuraw018
    if  djuraw007 >= R1    R0  = 0.996467 * djuraw016
    if  djuraw000 > R0    if  R0 <= djuraw005    R0  = 0.968677 * djuraw003
    R1  = 0.950166 * djuraw013
    if  R0 < djuraw001    if  R0 <= djuraw005    R0  = 0.968677 * djuraw003
    if  djuraw017 > R0    if  djuraw008 < R0    if  djuraw000 > R1    return  1
    
    R1 = R0 = undef
    R0  = 0.386411 * bvspraw000
    R1  = 0.967196 * bvspraw005
    if  R1 < bvspraw002    if  R1 < bvspraw008    R1  = 0.683208 * bvspraw006
    if  R1 >= bvspraw020    if  R0 < bvspraw016    if  bvspraw007 > R0    return  1
    
    R1 = R0 = undef
    R1  = 0.948355 * bvspraw006
    if  bvspraw020 <= R1    R0  = 0.999571 * bvspraw006
    if  bvspraw003 >= R0    if  bvspraw003 > R0    R0  = 0.97461 * bvspraw005
    if  bvspraw003 >= R0    R1  = 0.941123 * bvspraw018
    if  bvspraw020 <= R1    if  bvspraw016 < R1    R0  = 0.97461 * bvspraw005
    if  bvspraw008 >= R0    R0  = 0.921583 * bvspraw013
    if  bvspraw021 < R0    if  R0 >= R1    if  bvspraw021 < R0    return  1
    
    R0 = R1 = undef
    R1  = 0.992148 * aordraw012
    R0  = 0.977981 * aordraw004
    if  aordraw002 > R0    if  aordraw000 >= R1    if  R1 < aordraw005    if  aordraw011 < R0    R1  = 0.990964 * aordraw018
    if  R1 < aordraw004    R1  = 0.98734 * aordraw003
    if  R1 > aordraw013    if  R1 > aordraw006    return  1
    
    The training data had 5310 simulated trades starting 1993-06-04 through 2014-07-03.

    The out-of-sample evaluation data had 2275 simulated trades starting 2014-07-07 through 2023-07-28 with
    total return 87.34% (not including dividends or trading costs); compound annual return 7.17%; mean return 0.0276%; median return 0.0000%; winning percent 49.71

    The evaluation period with the generated rules applied had 1769 simulated, one-trading-day trades (77.76% of the total evaluation trading days) with
    total return 962.69% (not including dividends or trading costs); compound annual return 29.78%; mean return 0.1337%; median return 0.0465%; winning percent 51.67

    If trades on consecutive trading days were combined (total return unchanged), there would have been 284 trades with
    mean return 0.8357%; median return 0.3711%; winning percent 55.63
    The combined trades would have lasted from 1 to 48 trading days with a mean 6.23 trading days and a median 4 trading days.

    Each individual rule had better performance per trade on the out-of-sample data than the equivalent buy-and-hold trades. I think there is a reasonable chance the rules would have better performance than buy-and-hold trades in the future.
     
  9. ph1l

    ph1l

    The previous examples in this thread all had fixed-length inputs. This example has generated rules from variable-length inputs from different assets for simulating trades in another asset.

    A short summary of the method is
    • Find three value swings of past data for the input assets.
    • Fit a curve with a mathematical function to the value swings.
    • Create rules for trading a target asset based on parameters of the function and its output.


    Here is a more detailed explanation.

    Source of Input Data

    The input assets are daily close values from the following:
    Code:
    name                                           yahoo finance symbol    prefix
    ALL ORDINARIES                                 ^AORD                   aord
    BEL 20                                         ^BFX                    bfx
    CAC 40                                         ^FCHI                   cac40
    CBOE Volatility Index                          ^VIX                    vix
    DAX PERFORMANCE-INDEX                          ^GDAXI                  gdaxi
    Dow Jones Industrial Average                   ^DJI                    dji
    Dow Jones Transportation Average               ^DJT                    djt
    Dow Jones Utility Average                      ^DJU                    dju
    HANG SENG INDEX                                ^HSI                    hsi
    IBEX 35                                        ^IBEX                   ibex
    IBOVESPA                                       ^BVSP                   bvsp
    IDX COMPOSITE                                  ^JKSE                   jkse
    IPC MEXICO                                     ^MXX                    mxx
    NASDAQ 100                                     ^NDX                    nd100
    NASDAQ Bank                                    ^BANK                   ndbank
    NASDAQ Biotechnology                           ^NBI                    nbi
    NASDAQ Composite                               ^IXIC                   ixic
    NASDAQ Financial 100                           ^IXF                    ndfin
    NASDAQ Industrial                              ^INDS                   ndind
    NASDAQ Insurance                               ^INSR                   ndinsr
    NASDAQ Transportation                          ^TRAN                   ndtran
    NYSE ARCA OIL and GAS INDEX                    ^XOI                    xoi
    NYSE COMPOSITE (DJ)                            ^NYA                    nya
    Nikkei 225                                     ^N225                   n225
    PHLX GOLD and SILVER SECTOR Index              ^XAU                    xau
    PHLX Utility Sector                            ^UTY                    uty
    Russell 1000                                   ^RUI                    rui
    Russell 2000                                   ^RUT                    rut
    Russell 3000                                   ^RUA                    rua
    S&P 100                                        ^SP100                  sp100
    S&P 500 Consumer Discretionary (Sector)        ^SP500-25               spcd
    S&P 500 Consumer Staples (Sector)              ^SP500-30               spcst
    S&P 500 Energy (Sector)                        ^GSPE                   spenrg
    S&P 500 Financials (Sector)                    ^SP500-40               spfin
    S&P 500 Health Care (Sector)                   ^SP500-35               sphe
    S&P 500 Industrials (Sector)                   ^SP500-20               spind
    S&P 500 Information Technology (Sector)        ^SP500-45               sptech
    S&P 500 Materials (Sector)                     ^SP500-15               spmat
    S&P 500 Telecommunication Services (Sector)    ^SP500-50               sptel
    S&P 500 Utilities (Sector)                     ^SP500-55               sput
    S&P 500                                        ^GSPC                   gspc
    S&P 600                                        ^SP600                  sp600
    S&P MID CAP 400 INDEX                          ^MID                    mid
    S&P/ASX 200                                    ^AXJO                   asx200
    S&P/TSX Composite index                        ^GSPTSE                 gsptse
    TA-125                                         ^TA125.TA               ta125
    Treasury Bill 13 Week                          ^IRX                    irx
    Treasury Yield 10 Years                        ^TNX                    tnx
    Treasury Yield 30 Years                        ^TYX                    tyx
    Treasury Yield 5 Years                         ^FVX                    fvx
    Wilshire 5000 Total Market Index               ^W5000                  w5000
    
    
    I chose these assets because data for at least 30 years is available from Yahoo Finance.

    For inputs to the method, the data for the local date associated with an asset is grouped together as input for that date. For example, the 2024-01-10 data is grouped with other 2024-01-10 data even though markets in Australia have already closed for January 11. When non-U.S. markets are closed, the previous close values are carried forward until their dates match the U.S. market close date.


    Defining Input Value Swings

    For each date in a symbol's data, the software finds data for three value swings with algorithm
    • The swing direction starts as undefined.
    • A lookback period is the past N bars or to the bar just past the previous value swing whichever is larger.
    • If no close value in the lookback period is higher than the current close value, the swing direction is up.
    • If no close value in the lookback period is lower than the current close value, the swing direction is down.
    • If the swing direction is up and down on the same bar (e.g., value hasn't changed since last swing), the swing direction does not change.
    • If the swing direction changes from not up to up, a low swing has been detected at the oldest bar with the lowest value in the lookback period.
    • If the swing direction changes from not down to down, a high swing has been detected at the oldest bar with the highest value in the lookback period.
    • The first swing found is ignored.


    Modeling Input Value Swings

    The software fits a curve for the data from the current bar to the bar after the value swing that came before the three value swings was detected. The fitted curve has a least squares regression line added to zero or more asymmetric triangle waves.
    asymmetric_triangle_wave.png

    Here is an example with the close values of the NASDAQ 100 index for 39 trading days from 2023-11-16 through 2024-01-12 with the least squares regression line and fitted curve.
    nd100_20231116_20240112_39.png

    The corresponding fitted curve formula is:
    Code:
    nd100_20240112_cly = 16881.927734375 + 551.884216308594 * -0.0502413419724309 * x  +  209.763610839844 * (
        atri(1.1723438501358, 22.5762538909912, 0.833862066268921, 0.565416514873505, x)
        + atri(0.548687338829041, 10.0181884765625, 0.412693917751312, 0.470283389091492, x)
        + atri(0.40699827671051, 7.98540878295898, 0.176088511943817, 0.500997245311737, x)
        + atri(0.368489861488342, 38.861083984375, 0.150145471096039, 0.492421269416809, x)
        + atri(0.325989842414856, 18.3074150085449, 0.756223797798157, 0.466294586658478, x) ) ;
    
    atri(amplitude, period, phase, peakPhase, x) would be evaluated as the asymmetric triangle wave value for x bars before the current bar.

    To allow more relevant comparisons of phases like 0.833862066268921, the curve start at the most recent bar and continues backwards in time.

    To allow more relevant comparisons of least squares regression line slopes like -0.0502413419724309, the estimated standard deviation of the data (e.g., 551.884216308594) is factored out.

    To allow more relevant comparisons of amplitudes like 1.1723438501358, the estimated standard deviation of the differences of close values to the least squares regression line (e.g., 209.763610839844) is factored out.


    Creating Inputs for Rules Generator

    The inputs for the rules generator are prefixed with the prefix representing a symbol with some having the index of an asymmetric triangle wave (0 has highest amplitude, 1 has the next highest, etc.). The inputs are derived from the fitted curve parameters and/or values from evaluating the fitted curve:
    Code:
    bars -- number of bars in the three swing pattern
    example: aordbars
    
    fitProp -- proportion of cyclic data fitted by the asymmetric triangle waves
    example: aordclfitProp
    
    dtwFitProp -- proportion of cyclic data fitted by the asymmetric triangle waves using dynamic time warping
    example: aordcldtwFitProp
    
    trendsds -- number of estimated standard deviations of distances to the least squares regression line
    in the rise (+) or fall (-) of the regression line in the three swing pattern
    example: aordcl_trendsds
    
    bartrendsds -- number of estimated standard deviations of distances to the least squares regression line
    in the rise (+) or fall (-) of each bar the regression line in the three swing pattern
    example: aordcl_bartrendsds
    
    wsum -- sum of all the asymmetric triangle wave values at the current bar
    example: aordcl_wsum
    
    lpr01 -- log of (extrapolated price one bar ahead divided by current price) * 100
    example: aordlpr01cl
    
    lpr12 -- log of (extrapolated price two bars ahead divided extrapolated price one bar ahead) * 100
    example: aordlpr12cl
    
    wave -- asymmetric triangle wave value at the current bar
    example: aordcl_wave_0
    
    wprop -- asymmetric triangle wave value at the current bar divided by the wave amplitude
    example: aordcl_wprop_0
    
    amp -- asymmetric triangle wave amplitude
    example: aordcl_amp_0
    
    per -- asymmetric triangle wave period
    example: aordcl_per_0
    
    ncy -- number of cycles of an asymmetric triangle wave in the three swing pattern
    example: aordcl_ncy_0
    
    vel -- absolute vertical movement per bar for an asymmetric triangle wave in the three swing pattern
    example: aordcl_vel_0
    
    lvel -- absolute vertical movement per bar from trough to peak for an asymmetric triangle wave in the three swing pattern
    example: aordcl_lvel_0
    
    rvel -- absolute vertical movement per bar from peak to trough for an asymmetric triangle wave in the three swing pattern
    example: aordcl_rvel_0
    
    phase -- phase of an asymmetric triangle wave in the three swing pattern
    example: aordcl_phase_0
    
    offsetphase -- -0.5 + phase of an asymmetric triangle wave in the three swing pattern
    example: aordcl_offsetphase_0
    
    peakphase -- peak phase of an asymmetric triangle wave in the three swing pattern
    example: aordcl_peakphase_0
    
    offsetpeakphase -- -0.5 + peak phase of an asymmetric triangle wave in the three swing pattern
    example: aordcl_offsetpeakphase_0
    
    The target for the rules generator simulates a long trade entering at the next bar's close value and exiting at the following bar's close value (no adjustments for slippage or commission).

    This example uses 5253 instances of training data with simulated entries from 1994-02-23 through 2015-01-02 and 2251 instances of evaluation data with simulated entries from 2015-01-05 through 2023-12-21.


    Generating Rules

    The rules generator uses genetic programming to classify whether to take a trade or not. Each rule in a set of rules has one or more conditions logically ANDed together. Conditions can have inputs compared with constants or other inputs. When a rule returns 1, a long trade at the close of the next bar would be entered, and this trade would exit at the bar following entry.

    After the rules generator finishes its runs using the training data, a subset is chosen as the final rules for forward testing.

    Rules found for the NASDAQ 100 are:
    Code:
    if  gsptsebars >= 50    if  gsptselpr01cl <= 0.180333    if  gsptsecl_wprop_0 >= -0.658776    if  gsptsecl_rvel_0 > 0.0648147    if  gsptsecl_lvel_1 < 0.176615    if  gsptsecl_wsum <= 1.3634    if  gsptsecl_wave_1 >= -0.192705    if  gsptsecl_rvel_0 >= 0.0690005    if  gsptsebars > 49    return  1
    
    if  sptechcl_ncy_0 < 1.20559    if  sptechcl_wprop_1 <= 0.95901    if  sptechlpr01cl >= -0.431104    if  sptechcl_ncy_0 < 1.20804    if  sptechlpr01cl > -0.576447    if  sptechcl_ncy_0 >= 1.09133    if  sptechcl_amp_0 < 1.24989    if  sptechcl_offsetphase_0 >= -0.350003    return  1
    
    if  gsptsebars > 49    if  gsptsebars >= 50    if  gsptselpr01cl <= 0.134077    if  gsptsecl_ncy_0 >= 1.10754    if  gsptsecl_offsetphase_1 >= -0.286188    if  gsptsecl_phase_0 <= 0.917072    if  gsptsecl_lvel_1 < 0.174925    if  gsptsecl_wsum < 1.26999    return  1
    
    if  ndinsrcl_phase_1 < 0.587518    if  ndinsrlpr01cl <= 0.0229777    if  ndinsrcl_wave_0 <= 0.934144    if  ndinsrlpr12cl < 0.296799    if  ndinsrcl_lvel_1 <= 0.117298    if  ndinsrcl_wprop_0 <= 0.966144    return  1
    
    if  sptechcl_lvel_0 <= 0.187625    if  sptechcl_phase_0 >= 0.322132    if  sptechcl_ncy_0 >= 1.08671    if  sptechcl_wprop_1 <= 0.973641    if  sptechcl_wprop_0 >= -0.878743    if  sptechlpr12cl < 0.660802    if  sptechcl_ncy_0 <= 1.20559    if  sptechlpr01cl >= -0.637203    return  1
    
    if  w5000cl_offsetphase_0 <= 0.299248    if  w5000cl_ncy_0 >= 1.61404    if  w5000cl_trendsds > -2.94143    if  w5000lpr12cl < 0.282786    if  w5000cl_lvel_0 > 0.143781    if  w5000cl_phase_0 <= 0.80247    if  w5000cl_phase_0 <= 0.799542    if  w5000cl_wave_1 > -0.0348898    return  1
    
    if  asx200cl_wprop_1 < 0.876702    if  asx200cl_amp_1 >= 0.451709    if  asx200cl_amp_1 < 0.73843    if  asx200cl_per_1 < 30.0989    if  asx200cl_lvel_1 > 0.0462801    if  asx200cl_wave_0 >= 0.326522    if  asx200cl_amp_1 >= 0.451709    if  asx200cl_rvel_0 > 0.099337    if  asx200cl_wsum > 0.294748    return  1
    
    if  djulpr12cl >= -0.119748    if  djucl_per_0 >= 35.1501    if  djucl_lvel_0 > djucl_rvel_0    if  djucl_phase_0 > 0.14216    if  djulpr12cl >= -0.119748    if  djucl_amp_1 < 0.66725    if  djucl_per_0 >= 35.1501    if  djucl_lvel_0 <= 0.163034    return  1
    
    if  nbilpr12cl < 0.199289    if  nbicl_wave_0 > -0.383525    if  nbicl_trendsds <= 4.66456    if  nbicl_offsetphase_0 < -0.0186597    if  nbicl_lvel_0 < 0.135501    if  nbicl_rvel_1 <= 0.165058    if  nbilpr01cl < 0.201862    if  nbicl_offsetphase_0 <= 0.00157404    return  1
    
    if  sp600cl_wave_0 >= -0.714745    if  sp600cl_lvel_0 >= 0.0843772    if  sp600cl_wave_0 <= 1.00219    if  sp600bars >= 37    if  sp600cl_ncy_1 < 2.46636    if  sp600lpr01cl <= 0.387207    if  sp600cl_ncy_0 >= 1.17258    if  sp600bars >= 37    return  1
    
    if  nbicl_offsetphase_0 <= nbicl_phase_0    if  nbicl_offsetphase_0 <= -0.0201017    if  nbicl_ncy_1 <= 3.41247    if  nbilpr12cl < 0.193432    if  nbicl_trendsds <= 4.1589    if  nbicl_wprop_0 >= -0.744252    if  nbicl_lvel_0 <= 0.136218    return  1
    
    if  bfxcl_lvel_0 > 0.12984    if  bfxcl_lvel_0 <= 0.204981    if  bfxcl_ncy_1 <= 4.39151    if  bfxcl_per_0 > 21.4993    if  bfxcl_amp_1 >= 0.538709    if  bfxcl_phase_0 > 0.301409    if  bfxcl_offsetphase_0 >= -0.27477    return  1
    
    if  djicl_offsetphase_0 < -0.00246853    if  djicl_rvel_1 >= 0.05449    if  djicl_lvel_0 > djicl_rvel_0    if  djicl_lvel_0 >= 0.0752994    if  djicl_wprop_1 > -0.193109    if  djicl_phase_1 < 0.772738    if  djicl_rvel_1 >= 0.05449    if  djicl_ncy_1 < 3.74095    if  djicl_amp_1 <= 1.06974    return  1
    
    if  spcdcl_offsetphase_0 < 0.0618283    if  spcdcl_bartrendsds < 0.176386    if  spcdcl_phase_0 < 0.543865    if  spcdcl_wave_1 > -0.637746    if  spcdcl_lvel_0 >= 0.128471    if  spcdcl_lvel_0 >= 0.123029    if  spcdcl_rvel_1 > 0.0738231    if  spcdcl_offsetphase_1 > 0.128175    return  1
    
    if  sptelcl_offsetphase_1 > -0.0968448    if  sptelcl_per_1 <= 15.7406    if  sptelcl_lvel_1 < 0.370058    if  sptelcl_ncy_0 <= 2.1659    if  sptelcl_wprop_1 < 0.876375    if  sptelcl_lvel_0 > 0.142592    if  sptelcl_lvel_0 > 0.142054    if  sptelcl_lvel_0 > 0.142054    return  1
    
    if  rutcl_ncy_1 < 3.14879    if  rutcl_rvel_0 <= rutcl_lvel_0    if  rutlpr12cl < 0.190288    if  rutcl_wave_0 > -1.0056    if  rutcl_ncy_0 > 1.17494    if  rutcl_lvel_1 <= 0.151642    if  rutlpr12cl < 0.190288    return  1
    
    if  ruacl_ncy_0 >= 1.0421    if  ruacl_bartrendsds >= -0.0701428    if  rualpr12cl >= -1.87237    if  rualpr12cl < -0.169257    if  rualpr01cl < -0.3675    if  ruacl_wprop_0 < 0.987579    if  ruacl_ncy_0 < 3.31658    if  rualpr12cl < -0.304058    if  ruacl_wave_0 >= -0.246811    return  1
    
    if  ruacl_wave_0 > -0.6948    if  ruacl_rvel_1 <= ruacl_lvel_1    if  ruacl_wprop_0 <= 0.999565    if  rualpr12cl <= -0.384271    if  ruacl_trendsds > -3.4272    if  ruacl_ncy_0 > 1.04294    if  rualpr12cl <= -0.384271    if  ruacl_trendsds > -3.4272    return  1
    
    if  spfincl_per_1 <= 26.8685    if  spfincl_wave_1 > -0.189383    if  spfincl_wave_1 >= -0.161    if  spfincl_wprop_0 <= 0.983375    if  spfincl_wave_0 >= -0.58717    if  spfincl_per_0 <= 31.6072    if  spfincl_amp_0 < 1.02032    return  1
    
    if  sp600cl_lvel_0 > 0.0835371    if  sp600cl_wprop_0 <= 0.94178    if  sp600lpr01cl <= 0.355109    if  sp600bars > 40    if  sp600cl_per_1 >= 21.0496    if  sp600cl_ncy_1 <= 2.53135    if  sp600lpr01cl <= 0.355109    if  sp600cl_lvel_0 > 0.0832733    if  sp600cl_wprop_1 >= -0.505798    return  1
    
    if  sp100cl_wprop_0 < 0.684285    if  sp100cl_rvel_1 < sp100cl_lvel_1    if  sp100cl_wsum > -0.269601    if  sp100cl_wave_0 < 0.912238    if  sp100cl_wsum > -0.269601    if  sp100cl_offsetphase_0 > -0.354417    if  sp100cl_trendsds <= 1.95873    if  sp100cl_ncy_0 >= 1.22392    if  sp100cl_wprop_0 < 0.672633    return  1
    
    if  n225cl_ncy_0 <= 1.37116    if  n225lpr01cl > -0.512516    if  n225cl_rvel_1 <= 0.125867    if  n225cl_lvel_1 <= 0.121976    if  n225cl_offsetphase_0 <= 0.498048    if  n225cl_wprop_0 <= 0.701871    if  n225cl_ncy_0 <= 1.37116    if  n225cl_bartrendsds < 0.0581231    if  n225lpr01cl > -0.512516    return  1
    
    if  xoilpr01cl > -0.317378    if  xoicl_lvel_1 >= xoicl_rvel_1    if  xoicl_amp_0 < 1.19832    if  xoicl_rvel_0 <= xoicl_lvel_0    if  xoicl_amp_0 <= 1.1726    if  xoicl_phase_1 <= 0.664929    return  1
    
    if  spfincl_offsetphase_1 < spfincl_phase_1    if  spfincl_amp_0 <= 1.01345    if  spfincl_per_1 <= 25.1463    if  spfincl_wave_0 >= -0.421303    if  spfincl_wave_1 >= -0.161709    if  spfincl_rvel_0 > 0.0965003    if  spfincl_wave_0 < 0.8804    if  spfincl_wave_0 >= -0.421303    if  spfincl_wave_0 >= -0.421303    return  1
    
    if  ndinsrcl_wave_1 >= -0.754112    if  ndinsrcl_rvel_1 <= 0.136736    if  ndinsrcl_ncy_0 >= 1.68728    if  ndinsrcl_amp_1 > 0.390133    if  ndinsrlpr12cl < 0.280531    if  ndinsrlpr01cl < 0.440081    if  ndinsrcl_amp_1 > 0.390133    if  ndinsrcl_phase_0 > 0.0562328    return  1
    
    if  n225cl_wprop_0 < 0.70024    if  n225cl_ncy_0 <= 1.37337    if  n225lpr01cl >= -0.51776    if  n225cl_wave_1 < 0.593395    if  n225lpr12cl <= 0.913939    if  n225cl_wprop_0 < 0.792009    if  n225lpr01cl >= -0.51776    if  n225cl_lvel_1 <= 0.122734    if  n225cl_ncy_1 < 6.07028    return  1
    
    if  spenrgcl_rvel_0 <= 0.178898    if  spenrgcl_wave_1 > 0.160525    if  spenrgcl_rvel_0 < 0.139509    if  spenrgcl_wave_1 > 0.147221    if  spenrgcl_rvel_0 < 0.139509    if  spenrgcl_lvel_0 > 0.082349    if  spenrgcl_wsum < 1.51997    if  spenrgcl_per_1 < 33.2069    return  1
    
    if  nyacl_amp_0 <= 1.37292    if  nyalpr01cl <= 0.308411    if  nyacl_amp_0 < 1.24746    if  nyacl_wave_0 >= 0.397509    if  nyacl_lvel_0 > nyacl_rvel_0    if  nyacl_per_1 <= 28.0804    if  nyacl_lvel_1 > 0.0514567    if  nyalpr12cl <= 0.929302    if  nyacl_wave_0 >= 0.161891    return  1
    
    if  nyacl_rvel_0 < nyacl_lvel_0    if  nyacl_rvel_0 > 0.0554896    if  nyacl_wprop_0 >= 0.550856    if  nyacl_phase_0 < 0.461132    if  nyalpr12cl <= 0.925539    if  nyacl_per_1 <= 31.6198    if  nyacl_wave_0 >= 0.411132    if  nyacl_phase_0 < 0.461132    return  1
    
    if  nd100cl_wsum >= 0.0434539    if  nd100cl_wave_1 <= 0.238033    if  nd100lpr12cl <= 0.106459    if  nd100cl_wave_1 < 0.233823    if  nd100cl_lvel_1 > 0.0605134    if  nd100cl_wsum < 1.29088    if  nd100cl_offsetphase_0 > -0.227007    if  nd100cl_rvel_1 > 0.0636087    if  nd100cl_ncy_1 > 2.57203    return  1
    
    

    Performance

    For the evaluation period, simulated buy and hold performance was
    total return 260.94%, compound annual return 15.40%, maximum drawdown 35.56%, daily mean result 0.0570%, daily mean win 0.9259%, daily mean loss 1.0175%, number of trading days 2251, number of daily wins 1250, daily win rate 55.53%

    The simulated performance using the rules for the evaluation period was
    total return 1706.05%, compound annual return 38.10%, maximum drawdown 8.83%, mean result 0.1477%, mean win 0.8963%, mean loss 0.8530%, number of trades 1961, number of wins 1126, win rate 57.42%


    Other Targets

    Potential targets in addition to the NASDAQ 100 based on mapping to ETFs for actual trading and three-year, daily return correlations (QuantDare method) are in the attached corrmatrix.csv (semicolon-separated).
     
  10. ph1l

    ph1l

    Using the same method and data as above, the rules for IBOVESPA (Brazil)
    Code:
    if  djicl_ncy_1 <= 3.97268    if  djicl_amp_0 < 1.55384    if  djicl_offsetphase_0 <= -0.0132263    if  djicl_rvel_1 >= 0.0541881    if  djilpr01cl <= 0.140991    if  djilpr01cl <= 0.140991    if  djicl_lvel_0 >= 0.128096    if  djicl_lvel_0 >= 0.128096    if  djicl_rvel_0 <= 0.377881    return  1
    
    if  nbicl_amp_0 < 1.72229    if  nbicl_amp_1 > 0.628997    if  nbicl_amp_0 <= 1.56717    if  nbicl_wsum >= -0.589339    if  nbicl_amp_1 > 0.628376    if  nbicl_rvel_0 < 0.181423    if  nbicl_rvel_0 < 0.193878    if  nbicl_wprop_0 <= 0.943634    if  nbicl_wave_0 > -0.869427    return  1
    
    if  djicl_rvel_0 > 0.102279    if  djicl_phase_0 <= 0.501138    if  djicl_rvel_1 > 0.0512203    if  djilpr01cl <= 0.16067    if  djicl_rvel_0 <= 0.376304    if  djilpr01cl < 0.156685    if  djicl_ncy_0 > 1.34807    if  djicl_lvel_0 > 0.145273    if  djicl_ncy_1 <= 5.36803    return  1
    
    if  bfxcl_amp_0 > 0.908939    if  bfxcl_offsetphase_1 >= -0.258078    if  bfxcl_amp_0 < 1.32304    if  bfxcl_phase_0 >= 0.248451    if  bfxcl_wave_1 <= 0.672789    if  bfxcl_phase_0 <= 0.430597    if  bfxcl_per_1 > 8.35079    return  1
    
    if  bfxcl_phase_0 <= 0.433642    if  bfxcl_per_1 >= 8.3298    if  bfxcl_phase_0 < 0.438131    if  bfxcl_per_1 >= 7.70378    if  bfxcl_offsetphase_1 > -0.263076    if  bfxcl_amp_0 <= 1.29665    if  bfxcl_amp_0 > 0.921293    if  bfxcl_wave_0 >= 0.0982673    return  1
    
    if  spenrgcl_lvel_0 > 0.0872609    if  spenrgcl_per_0 >= 31.4703    if  spenrgcl_lvel_0 < 0.137476    if  spenrgcl_bartrendsds > -0.0778304    if  spenrgbars <= 65    if  spenrgbars >= 41    if  spenrgcl_offsetphase_1 <= 0.207699    if  spenrgcl_per_0 > 32.9472    return  1
    
    if  tnxcl_lvel_1 < 0.330599    if  tnxcl_lvel_1 > 0.0686704    if  tnxcl_lvel_1 > 0.0829088    if  tnxcl_per_0 < 33.2852    if  tnxcl_rvel_0 <= 0.293689    if  tnxcl_ncy_0 > 1.4499    if  tnxcl_ncy_1 <= 6.29766    if  tnxcl_bartrendsds > 0.0186923    return  1
    
    if  bvspcl_offsetphase_0 < 0.0657059    if  bvsplpr01cl > -0.0686255    if  bvsplpr12cl > 0.314165    if  bvspcl_trendsds < 3.33793    if  bvspcl_wprop_1 >= -0.938046    if  bvspcl_offsetphase_0 <= 0.0700438    if  bvspcl_wave_0 <= 0.955152    if  bvspcl_wave_0 >= -0.998227    if  bvsplpr01cl >= -0.110323    return  1
    
    if  bfxcl_phase_0 < 0.432821    if  bfxcl_per_0 > 30.0378    if  bfxcl_wave_1 < 0.435031    if  bfxcl_rvel_0 >= 0.0677167    if  bfxcl_offsetphase_0 > -0.495088    if  bfxcl_ncy_0 >= 1.0496    if  bfxcl_amp_0 <= 1.38842    if  bfxcl_amp_0 <= 1.38842    if  bfxcl_amp_0 >= 0.885921    return  1
    
    if  djucl_ncy_1 < 3.80688    if  djucl_offsetphase_0 >= -0.163343    if  djubars > 48    if  djucl_wave_0 < 0.84974    if  djucl_lvel_0 <= 0.186965    if  djucl_phase_1 >= 0.361888    if  djucl_per_0 >= 20.1723    if  djubars > 49    return  1
    
    if  spenrgcl_lvel_1 >= 0.155712    if  spenrgcl_lvel_1 >= 0.155712    if  spenrgcl_wsum <= 0.672103    if  spenrgcl_lvel_1 <= 0.244708    if  spenrgcl_rvel_0 >= 0.110098    if  spenrgcl_offsetphase_1 <= 0.435785    if  spenrgcl_lvel_1 <= 0.244708    if  spenrgcl_rvel_0 >= 0.110098    return  1
    
    if  utycl_ncy_0 >= 1.74566    if  utycl_phase_1 > 0.0183895    if  utylpr12cl <= 0.74144    if  utycl_ncy_1 <= 3.18553    if  utylpr12cl >= -0.207678    if  utycl_per_0 <= 36.1657    if  utycl_ncy_0 >= 1.74566    if  utycl_phase_1 > 0.0158539    if  utycl_phase_1 > 0.0158539    return  1
    
    if  spcdcl_phase_0 < 0.853743    if  spcdcl_ncy_1 <= 6.66251    if  spcdcl_wave_1 > -0.559536    if  spcdbars <= 51    if  spcdcl_wave_1 < 0.113647    if  spcdcl_amp_0 > 0.929272    if  spcdcl_rvel_1 >= 0.0843594    if  spcdbars <= 51    return  1
    
    if  tnxcl_lvel_1 > 0.0788579    if  tnxcl_rvel_0 <= 0.310607    if  tnxcl_ncy_1 <= 5.30794    if  tnxcl_ncy_0 >= 1.45612    if  tnxcl_bartrendsds > 0.0154065    if  tnxcl_wave_0 > -0.905015    if  tnxcl_bartrendsds > 0.00511675    if  tnxcl_lvel_1 > 0.0788579    if  tnxcl_ncy_0 < 2.35492    return  1
    
    if  cac40cl_rvel_0 <= 0.413461    if  cac40cl_amp_0 > 0.648987    if  cac40cl_amp_0 < 1.23144    if  cac40cl_amp_0 < 1.17337    if  cac40cl_phase_1 <= 0.907271    if  cac40cl_rvel_0 >= 0.192121    if  cac40cl_lvel_0 >= 0.243219    if  cac40cl_lvel_0 >= 0.243766    return  1
    
    if  cac40cl_lvel_0 > 0.243062    if  cac40cl_rvel_0 >= 0.202346    if  cac40cl_phase_1 <= 0.738864    if  cac40bars > 21    if  cac40cl_rvel_0 < 0.400061    if  cac40cl_lvel_0 > 0.241034    if  cac40cl_amp_1 <= 0.995043    if  cac40cl_rvel_0 > 0.203703    return  1
    
    if  ta125cl_wprop_0 >= -0.864933    if  ta125cl_amp_0 >= 0.961601    if  ta125cl_rvel_1 > 0.0660379    if  ta125lpr01cl <= 0.567576    if  ta125cl_per_1 >= 9.54008    if  ta125cl_per_1 < 25.6094    if  ta125lpr01cl < 0.684532    if  ta125cl_rvel_1 <= 0.204975    if  ta125cl_ncy_0 < 1.28982    return  1
    
    if  sputcl_per_1 > 32.3274    if  sputcl_per_1 > 32.3274    if  sputcl_per_1 <= 64.8713    if  sputcl_per_1 <= 65.3726    if  sputcl_wave_0 <= 1.02991    if  sputcl_wave_0 < 0.98447    if  sputcl_amp_1 <= 0.713777    if  sputcl_lvel_0 <= 0.323458    return  1
    
    if  spcdlpr01cl <= 0.484533    if  spcdbars <= 49    if  spcdcl_offsetphase_0 <= 0.292815    if  spcdcl_wave_0 >= -0.596015    if  spcdlpr12cl <= -0.0403373    if  spcdcl_per_1 >= 12.1315    if  spcdcl_wave_0 <= 1.14238    if  spcdlpr01cl <= 0.515288    return  1
    
    if  hsilpr01cl <= -0.0750969    if  hsilpr01cl <= -0.0750969    if  hsicl_wprop_1 <= 0.986052    if  hsicl_wprop_0 < hsicl_wprop_1    if  hsicl_wprop_1 <= 0.981559    if  hsicl_wsum >= -1.67582    if  hsicl_wprop_0 < hsicl_wprop_1    if  hsicl_per_0 >= 25.1401    if  hsicl_wprop_1 >= hsicl_wprop_0    return  1
    
    if  spcdcl_offsetphase_0 <= 0.337918    if  spcdlpr01cl < 0.429633    if  spcdcl_per_1 > 12.2083    if  spcdlpr12cl < -0.067836    if  spcdbars <= 49    if  spcdcl_bartrendsds < 0.138021    if  spcdcl_per_1 > 12.2083    if  spcdcl_wave_1 >= -0.569274    if  spcdcl_bartrendsds < 0.138021    return  1
    
    if  djucl_phase_1 > 0.370835    if  djucl_lvel_0 <= 0.196517    if  djubars >= 49    if  djucl_ncy_1 <= 3.9283    if  djucl_ncy_1 <= 3.74913    if  djucl_offsetphase_0 >= -0.157513    if  djubars > 48    if  djucl_wave_0 <= 0.840477    return  1
    
    if  sputcl_per_1 < 65.4399    if  sputcl_per_1 > 32.1659    if  sputcl_wave_0 < 0.990482    if  sputcl_wave_1 < 0.52619    if  sputcl_amp_1 < 0.724466    if  sputcl_amp_1 < 0.74444    if  sputcl_rvel_1 <= 0.216302    if  sputcl_wave_0 < 1.04369    if  sputcl_per_1 < 65.4399    return  1
    
    if  spfincl_ncy_0 >= 1.41921    if  spfincl_wave_1 > -0.0124847    if  spfincl_rvel_1 >= 0.0413239    if  spfincl_ncy_0 >= 1.41921    if  spfincl_wprop_0 < 0.744351    if  spfincl_wave_1 > -0.0124847    if  spfincl_lvel_1 < 0.147589    return  1
    
    if  asx200cl_rvel_1 < 0.186032    if  asx200cl_amp_0 > 1.0886    if  asx200cl_ncy_0 <= 2.32097    if  asx200cl_rvel_0 < asx200cl_lvel_0    if  asx200cl_wprop_0 <= 0.842555    if  asx200cl_wsum > -0.883073    if  asx200cl_ncy_0 <= 2.32097    if  asx200cl_rvel_1 < 0.186032    if  asx200cl_amp_0 > 1.0886    return  1
    
    if  gdaxicl_wprop_0 < 0.59813    if  gdaxicl_wprop_1 <= gdaxicl_wprop_0    if  gdaxicl_amp_0 > 0.845356    if  gdaxicl_wprop_0 < 0.59813    if  gdaxicl_offsetphase_0 > -0.317979    if  gdaxicl_ncy_1 >= 1.26419    if  gdaxicl_amp_0 <= 1.15103    return  1
    
    if  asx200cl_wave_1 > -0.378914    if  asx200cl_wave_0 > -0.988337    if  asx200cl_lvel_0 > asx200cl_rvel_0    if  asx200cl_wprop_0 < 0.834253    if  asx200cl_ncy_0 < 1.88368    if  asx200cl_rvel_0 <= 0.235947    if  asx200cl_phase_1 <= 0.925126    if  asx200cl_ncy_1 < 8.7903    if  asx200cl_amp_0 > 1.08342    return  1
    
    As before, the simulated trades are enter long at the next day's close value, and exit at the following day's close value. The entry and exit days are always when U.S. stock markets were open. If the target market was closed those days, the previous actual trading day close was carried foward.

    The simulated performance of buy and hold for the evaluation period data with simulated entries from 2015-01-05 through 2023-12-21 is
    total return 123.282%, compound annual return 9.38%, maximum drawdown 47.58%, daily mean result 0.0356%, daily mean win 1.0967%, daily mean loss 1.0077%, number of trading days 2251, number of daily wins 1122, daily win rate 49.84%

    The simulated performance using the rules for the evaluation period data was
    total return 1096.94%, compound annual return 31.91%, maximum drawdown 11.26%, mean result 0.1340%, mean win 1.0980%, mean loss 0.9088%, number of trades 1854, number of wins 968, win rate 52.21%
     
    #10     Jan 16, 2024
    murray t turtle likes this.