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?
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 ?
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.
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.
%% 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]. Thanks
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. They combined some operators and technical indicators on individual stocks with a few fixed parameters 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.
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.
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.
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. 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. 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).
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%