diff --git a/pipeline_is_results.csv b/pipeline_is_results.csv new file mode 100644 index 0000000..c26964a --- /dev/null +++ b/pipeline_is_results.csv @@ -0,0 +1,253 @@ +filt,kind,param,hold,p_ret,p,is_cagr,is_sharpe,is_maxdd,name,bh,by +,vix_spike,1.05,5,0.23186905728715682,0.9098025090562097,0.004046750659648657,0.14993341259547585,-0.8674497440768423,vix_spike=1.05|H5|Fnan,False,False +,vix_spike,1.05,10,0.03889315146800972,0.05346637013101885,0.06538684396651573,0.3641079752804774,-0.781526735980781,vix_spike=1.05|H10|Fnan,False,False +,vix_spike,1.05,20,0.0616981516859197,0.2258732126632905,0.051415432477833756,0.3175965454236944,-0.8190365331722551,vix_spike=1.05|H20|Fnan,False,False +,vix_spike,1.08,5,0.045033634300708315,0.15239926526879005,0.052831641535623364,0.3342096043700541,-0.7410760358954781,vix_spike=1.08|H5|Fnan,False,False +,vix_spike,1.08,10,0.0158783860554467,0.006635729053244371,0.08942751839678542,0.45182527102692543,-0.7162925616967659,vix_spike=1.08|H10|Fnan,False,False +,vix_spike,1.08,20,0.0785960320421324,0.47810244046787564,0.044758896337864895,0.29575383342015443,-0.8163534619458387,vix_spike=1.08|H20|Fnan,False,False +,vix_spike,1.1,5,0.021151610504492224,0.0637694002980969,0.06437007567294617,0.4040090081809,-0.6282650092887803,vix_spike=1.1|H5|Fnan,False,False +,vix_spike,1.1,10,0.02358823161109913,0.05827416120098083,0.0710584672899679,0.40243801928079054,-0.6543485812997568,vix_spike=1.1|H10|Fnan,False,False +,vix_spike,1.1,20,0.08504673383068406,0.41294520122800865,0.041047525575622856,0.283477132473777,-0.7842762839610652,vix_spike=1.1|H20|Fnan,False,False +,vix_spike,1.12,5,0.0248822161027146,0.078257604705334,0.053094633416370884,0.3809800932567761,-0.4366333698071494,vix_spike=1.12|H5|Fnan,False,False +,vix_spike,1.12,10,0.02800571339211376,0.07364439088802029,0.0647885762920335,0.39472074523834544,-0.5222433179161381,vix_spike=1.12|H10|Fnan,False,False +,vix_spike,1.12,20,0.05584427240912487,0.174542004521682,0.05035201080753571,0.3192158679648455,-0.6862089671295577,vix_spike=1.12|H20|Fnan,False,False +,vix_spike,1.15,5,0.10111534757313632,0.22022860259247717,0.02334283007010396,0.24368118649763712,-0.3906781699604652,vix_spike=1.15|H5|Fnan,False,False +,vix_spike,1.15,10,0.2470136852714971,0.5488608583922397,0.007798091228578663,0.12957261974601186,-0.5280265309980647,vix_spike=1.15|H10|Fnan,False,False +,vix_spike,1.15,20,0.02319529033496274,0.10825270941357512,0.05693251434344759,0.3708294952982853,-0.4316772586946026,vix_spike=1.15|H20|Fnan,False,False +,vix_cross,17.0,5,0.13783548663568085,0.3184827596283648,0.012381575703294567,0.24271446114200232,-0.15952654804373234,vix_cross=17.0|H5|Fnan,False,False +,vix_cross,17.0,10,0.1559699912499763,0.48806984992927527,0.012469329702878174,0.2011458596299774,-0.1707032325139023,vix_cross=17.0|H10|Fnan,False,False +,vix_cross,17.0,20,0.05310716079116677,0.36491662006097536,0.027677099314039832,0.34367788180047887,-0.2894412324257224,vix_cross=17.0|H20|Fnan,False,False +,vix_cross,18.0,5,0.17138892191154104,0.33907621505731234,0.01125897454564595,0.21527551204385012,-0.18243514625368906,vix_cross=18.0|H5|Fnan,False,False +,vix_cross,18.0,10,0.19134117608255563,0.44709366889181856,0.013401636603895373,0.2036891960310375,-0.2500816895210626,vix_cross=18.0|H10|Fnan,False,False +,vix_cross,18.0,20,0.272059300085876,0.66546697912894,0.008569881830187587,0.13412942682618254,-0.31741196862331,vix_cross=18.0|H20|Fnan,False,False +,vix_cross,19.0,5,0.49116094740444805,0.6720517008794704,-0.002278830213069072,0.004657408663292134,-0.3780800976063379,vix_cross=19.0|H5|Fnan,False,False +,vix_cross,19.0,10,0.5658722228663143,0.8028923173839578,-0.007703545274536983,-0.038028500257960354,-0.44781305616507483,vix_cross=19.0|H10|Fnan,False,False +,vix_cross,19.0,20,0.4344118857732907,0.7883420383032556,-0.002981433350050855,0.03382417029825522,-0.46341931381283696,vix_cross=19.0|H20|Fnan,False,False +,vix_cross,20.0,5,0.2925091167826485,0.46048406019067845,0.0056048793166769695,0.1089845585810213,-0.31700920390213516,vix_cross=20.0|H5|Fnan,False,False +,vix_cross,20.0,10,0.3088814676599603,0.5416889071907488,0.006625899563688309,0.11570536244973627,-0.4536770615723775,vix_cross=20.0|H10|Fnan,False,False +,vix_cross,20.0,20,0.30887261029786006,0.6372945008945603,0.005610157330224963,0.1087386050291828,-0.5480106098301637,vix_cross=20.0|H20|Fnan,False,False +,vix_cross,22.0,5,0.7646982634494961,0.8609212576992508,-0.022203900549696787,-0.16336311321408825,-0.5530191183932165,vix_cross=22.0|H5|Fnan,False,False +,vix_cross,22.0,10,0.7011894577147268,0.8723864010984073,-0.025199939863543186,-0.11431384942925643,-0.635696370739857,vix_cross=22.0|H10|Fnan,False,False +,vix_cross,22.0,20,0.7310492960256105,0.9353724685049216,-0.039968757518548115,-0.15087086261744181,-0.8380568903258399,vix_cross=22.0|H20|Fnan,False,False +,vix_cross,25.0,5,0.9759654866327843,0.9901949569136005,-0.059289757212646066,-0.46164601695556756,-0.7869035055788995,vix_cross=25.0|H5|Fnan,False,False +,vix_cross,25.0,10,0.6426975700435076,0.8017177148683788,-0.02454153761830602,-0.07647623966980377,-0.7512413699852116,vix_cross=25.0|H10|Fnan,False,False +,vix_cross,25.0,20,0.5131746861704368,0.7532187402374206,-0.021065402391948096,-0.006993656933932437,-0.7973570686133038,vix_cross=25.0|H20|Fnan,False,False +,rsi2,5.0,5,0.045446618325321056,0.08545083628640401,0.05733096542652083,0.3455294459674733,-0.6832694879480132,rsi2=5.0|H5|Fnan,False,False +,rsi2,5.0,10,0.0845554286001612,0.3508753273270343,0.0428101972347541,0.2891623240133005,-0.7627945984522062,rsi2=5.0|H10|Fnan,False,False +,rsi2,5.0,20,0.07250548721499342,0.3647427364887835,0.0482098750507276,0.30702348862680295,-0.8296390703529309,rsi2=5.0|H20|Fnan,False,False +,rsi2,10.0,5,0.05882842179763881,0.1277580802528135,0.05138171781315237,0.32244462783037053,-0.7245560930648984,rsi2=10.0|H5|Fnan,False,False +,rsi2,10.0,10,0.0698789752303542,0.2296684329717484,0.04959329384627398,0.3121066317759991,-0.7711384239718434,rsi2=10.0|H10|Fnan,False,False +,rsi2,10.0,20,0.07588029328638204,0.4849189115200436,0.04661246439953648,0.3017179660166222,-0.8296390703529309,rsi2=10.0|H20|Fnan,False,False +,rsi2,15.0,5,0.03350263636061023,0.04517432994431553,0.06793360862140285,0.38158380010832993,-0.6995857687896974,rsi2=15.0|H5|Fnan,False,False +,rsi2,15.0,10,0.07055966988325635,0.24341419804342143,0.049393206477577056,0.31136101942390576,-0.7827244689121401,rsi2=15.0|H10|Fnan,False,False +,rsi2,15.0,20,0.07506478634076756,0.5345012241100006,0.0461710391513912,0.30024625641487146,-0.8296390703529309,rsi2=15.0|H20|Fnan,False,False +,rsi2,20.0,5,0.031043498656302043,0.03767260980333109,0.07014269020206387,0.3877192455844986,-0.6953591928443265,rsi2=20.0|H5|Fnan,False,False +,rsi2,20.0,10,0.07348538092999493,0.30127783812284353,0.04760389099857942,0.3052630889982055,-0.7892301969147344,rsi2=20.0|H10|Fnan,False,False +,rsi2,20.0,20,0.06632288819366117,0.17104902458585078,0.05039094820731038,0.3141848706146761,-0.8296390703529307,rsi2=20.0|H20|Fnan,False,False +,down_days,2.0,5,0.026105058129923458,0.037701608546254956,0.0683229553161897,0.3884277831310506,-0.6479799352296767,down_days=2.0|H5|Fnan,False,False +,down_days,2.0,10,0.09262459824342491,0.37739766116282086,0.03978775708961235,0.27881354183857165,-0.7504148316770001,down_days=2.0|H10|Fnan,False,False +,down_days,2.0,20,0.05643773062919316,0.0830699013958887,0.057208100195930145,0.3368157013600291,-0.8159809573816585,down_days=2.0|H20|Fnan,False,False +,down_days,3.0,5,0.0001380540554841701,0.0001320479221337519,0.12970970351169786,0.7161580962126374,-0.2970604025979515,down_days=3.0|H5|Fnan,True,False +,down_days,3.0,10,0.0018072229267039079,0.0008295716783577406,0.12005340313217672,0.5962371779561062,-0.4586767705973125,down_days=3.0|H10|Fnan,False,False +,down_days,3.0,20,0.03170062590322207,0.05863137990020653,0.07096304939937004,0.3911637780793498,-0.6941678014176599,down_days=3.0|H20|Fnan,False,False +,down_days,4.0,5,0.004783304297770245,0.009020879007613255,0.0627793036534845,0.5092847799177956,-0.35778802507921337,down_days=4.0|H5|Fnan,False,False +,down_days,4.0,10,0.020726304364671978,0.051770357062067875,0.05278909456727221,0.3828875793827523,-0.546182070929156,down_days=4.0|H10|Fnan,False,False +,down_days,4.0,20,0.1411971332404841,0.36838161414588655,0.023176931771007103,0.2134910923711392,-0.7307800251657253,down_days=4.0|H20|Fnan,False,False +,pullback,3.0,5,0.07630157475871417,0.13462827044101006,0.04467701712363459,0.2969629216102173,-0.77494368295283,pullback=3.0|H5|Fnan,False,False +,pullback,3.0,10,0.10510348505938448,0.26858913800545925,0.034624395791059914,0.2606350865449363,-0.8275597119040932,pullback=3.0|H10|Fnan,False,False +,pullback,3.0,20,0.06611516747753478,0.1189405856699832,0.05228180506514968,0.3214647612201571,-0.8296390703529308,pullback=3.0|H20|Fnan,False,False +,pullback,5.0,5,0.1269219375058242,0.21476978392055066,0.02858905267352596,0.2367874184867915,-0.6837199401176215,pullback=5.0|H5|Fnan,False,False +,pullback,5.0,10,0.24338577711365472,0.5170694315790212,0.0037231094130352194,0.14213756211909082,-0.7886573557271254,pullback=5.0|H10|Fnan,False,False +,pullback,5.0,20,0.09980172506983644,0.2044376787998574,0.03803885144890562,0.27273272096682166,-0.8296390703529313,pullback=5.0|H20|Fnan,False,False +,pullback,7.0,5,0.16995999079925136,0.26235390203119224,0.018954548185946107,0.19553419926927368,-0.6811016980641784,pullback=7.0|H5|Fnan,False,False +,pullback,7.0,10,0.21248845655526236,0.37239061900021797,0.009501265653054425,0.15945303699353272,-0.7622317421442026,pullback=7.0|H10|Fnan,False,False +,pullback,7.0,20,0.1658589731913924,0.3308508261400216,0.01888444660934363,0.2002808781637786,-0.828892395885948,pullback=7.0|H20|Fnan,False,False +50.0,vix_spike,1.05,5,0.11491690527520093,0.5124697871172941,0.030257906975612814,0.2663017103713767,-0.3951416549466913,vix_spike=1.05|H5|F50.0,False,False +50.0,vix_spike,1.05,10,0.029258068976247525,0.30797039033622725,0.05949187534499156,0.4054659041099349,-0.39460348658562294,vix_spike=1.05|H10|F50.0,False,False +50.0,vix_spike,1.05,20,0.026756617805732807,0.31289484747984087,0.06533074065422806,0.40855266549488806,-0.5760972437441589,vix_spike=1.05|H20|F50.0,False,False +50.0,vix_spike,1.08,5,0.029776428154773323,0.1569279771435376,0.046196979814163264,0.4087097871969418,-0.27654181062745853,vix_spike=1.08|H5|F50.0,False,False +50.0,vix_spike,1.08,10,0.002375138701744216,0.03923329081110501,0.0868920693387587,0.6036520056911016,-0.40089651784999913,vix_spike=1.08|H10|F50.0,False,False +50.0,vix_spike,1.08,20,0.03933002434363068,0.28680144135060165,0.060949738711198576,0.40890428201725415,-0.618188160906179,vix_spike=1.08|H20|F50.0,False,False +50.0,vix_spike,1.1,5,0.0038329606487395927,0.021198293906221178,0.058202959012690014,0.5787523966882088,-0.20230688596639457,vix_spike=1.1|H5|F50.0,False,False +50.0,vix_spike,1.1,10,0.0033619149010242493,0.033075461826677116,0.0731851128496277,0.5877591099708408,-0.29819406447548935,vix_spike=1.1|H10|F50.0,False,False +50.0,vix_spike,1.1,20,0.003901852529594752,0.051061843585310254,0.08169535131719807,0.5649131456256061,-0.3630918145268862,vix_spike=1.1|H20|F50.0,False,False +50.0,vix_spike,1.12,5,0.011534981259732263,0.04216032782515672,0.039535947463051446,0.4730592621780363,-0.17476250523338166,vix_spike=1.12|H5|F50.0,False,False +50.0,vix_spike,1.12,10,0.022599400500410018,0.10704062256273256,0.045362081464305426,0.4332885801747065,-0.2942642516603634,vix_spike=1.12|H10|F50.0,False,False +50.0,vix_spike,1.12,20,0.01662099062962401,0.12135631157390492,0.05599754926699285,0.44587726941512906,-0.3081603558247501,vix_spike=1.12|H20|F50.0,False,False +50.0,vix_spike,1.15,5,0.06655537112086682,0.14881244836833207,0.014948378598446554,0.28833633591814595,-0.11531400006271908,vix_spike=1.15|H5|F50.0,False,False +50.0,vix_spike,1.15,10,0.27388878825780694,0.5189073625929851,0.006580654954212006,0.12568489778364864,-0.2190827591307143,vix_spike=1.15|H10|F50.0,False,False +50.0,vix_spike,1.15,20,0.07763235435687708,0.2545789450197549,0.026488978499773497,0.3127253091893947,-0.25417028882303483,vix_spike=1.15|H20|F50.0,False,False +50.0,vix_cross,17.0,5,0.47400114611505456,0.6604836873264311,-0.0002545447743752538,0.01497814868874769,-0.15193611463939394,vix_cross=17.0|H5|F50.0,False,False +50.0,vix_cross,17.0,10,0.40520306774463993,0.6812702173182121,0.001252239105514752,0.05077043852582053,-0.20541518144215531,vix_cross=17.0|H10|F50.0,False,False +50.0,vix_cross,17.0,20,0.5043732494340046,0.8180849080716364,-0.0029457231746677914,-0.002451744001352129,-0.3401391480363678,vix_cross=17.0|H20|F50.0,False,False +50.0,vix_cross,18.0,5,0.2072326807429029,0.34951935382664684,0.007645543783726394,0.18921613290784808,-0.13627998422176035,vix_cross=18.0|H5|F50.0,False,False +50.0,vix_cross,18.0,10,0.12332742182112966,0.29087747006567183,0.014769206304998228,0.26320743060604407,-0.15377562275748247,vix_cross=18.0|H10|F50.0,False,False +50.0,vix_cross,18.0,20,0.5922276598237454,0.851759746259523,-0.0077938248357865,-0.05085739182853664,-0.34006209268497956,vix_cross=18.0|H20|F50.0,False,False +50.0,vix_cross,19.0,5,0.60717581241468,0.7290642373217975,-0.00387751820331228,-0.058872373737557646,-0.2531949836504068,vix_cross=19.0|H5|F50.0,False,False +50.0,vix_cross,19.0,10,0.4479272813687859,0.6543779439136954,-0.00027528014238598075,0.027317596785946283,-0.23932368826725336,vix_cross=19.0|H10|F50.0,False,False +50.0,vix_cross,19.0,20,0.8956323813803201,0.9747966336060477,-0.02644901885498263,-0.2747650691961257,-0.4745509101688966,vix_cross=19.0|H20|F50.0,False,False +50.0,vix_cross,20.0,5,0.5203202070406391,0.6599650422187473,-0.0023158437239217955,-0.011009133788715856,-0.22408735659910572,vix_cross=20.0|H5|F50.0,False,False +50.0,vix_cross,20.0,10,0.2705351186610266,0.4532038671761012,0.007700022835598563,0.13724238961140367,-0.3121689313765529,vix_cross=20.0|H10|F50.0,False,False +50.0,vix_cross,20.0,20,0.6382735583140622,0.8602123194179636,-0.013921725088251957,-0.080393161754053,-0.4890137834701248,vix_cross=20.0|H20|F50.0,False,False +50.0,vix_cross,22.0,5,0.28965018323161407,0.38029422398015067,0.005612049495321791,0.11502122187071354,-0.18162308515389602,vix_cross=22.0|H5|F50.0,False,False +50.0,vix_cross,22.0,10,0.39576018690863657,0.5559051821231125,1.0668957135751e-05,0.04897000138237283,-0.32140527492766935,vix_cross=22.0|H10|F50.0,False,False +50.0,vix_cross,22.0,20,0.35384561897082945,0.5306435222453404,0.003170193685026357,0.08776952989688734,-0.45699152025058143,vix_cross=22.0|H20|F50.0,False,False +50.0,vix_cross,25.0,5,0.8468104257876966,0.8821617201246715,-0.020600415710535613,-0.26196482592842635,-0.4220892607591551,vix_cross=25.0|H5|F50.0,False,False +50.0,vix_cross,25.0,10,0.35516118726048523,0.4580951784454355,0.002579396078043583,0.07521675137707483,-0.4096192339883439,vix_cross=25.0|H10|F50.0,False,False +50.0,vix_cross,25.0,20,0.20380470326760752,0.319747149254563,0.012981796598196649,0.1667396006118765,-0.39401121963538854,vix_cross=25.0|H20|F50.0,False,False +50.0,rsi2,5.0,5,0.01979877256409636,0.0959583270780798,0.051993046878439975,0.4450027080495945,-0.22381650858086855,rsi2=5.0|H5|F50.0,False,False +50.0,rsi2,5.0,10,0.03179841422309668,0.22508929336722366,0.053318491663371326,0.3992286684282221,-0.3417690711212784,rsi2=5.0|H10|F50.0,False,False +50.0,rsi2,5.0,20,0.013482138841563206,0.13031611723378178,0.07820308465402648,0.4864963147836796,-0.4326013305363653,rsi2=5.0|H20|F50.0,False,False +50.0,rsi2,10.0,5,0.03532658129468094,0.15132046416109304,0.04640349151099632,0.3983293278679488,-0.2420395436120888,rsi2=10.0|H5|F50.0,False,False +50.0,rsi2,10.0,10,0.03326801832605915,0.23697605410092296,0.05376643792720137,0.3990233002579942,-0.34824976200746427,rsi2=10.0|H10|F50.0,False,False +50.0,rsi2,10.0,20,0.030965728239339765,0.24957783039019704,0.06414883104008462,0.4166676336434801,-0.47774119406660953,rsi2=10.0|H20|F50.0,False,False +50.0,rsi2,15.0,5,0.015656255632238446,0.0830329067267737,0.0587731899434174,0.4782229942087543,-0.24771440614230122,rsi2=15.0|H5|F50.0,False,False +50.0,rsi2,15.0,10,0.029051651615051476,0.21849782333556028,0.05669702982182612,0.41236697815349754,-0.3421949234651599,rsi2=15.0|H10|F50.0,False,False +50.0,rsi2,15.0,20,0.035645265055987405,0.29639894134687006,0.05965522663868228,0.3931349229494862,-0.4708151111611315,rsi2=15.0|H20|F50.0,False,False +50.0,rsi2,20.0,5,0.0190179258686902,0.11194291216263978,0.055671866168017115,0.4508570536271904,-0.2329554148079408,rsi2=20.0|H5|F50.0,False,False +50.0,rsi2,20.0,10,0.04161392027410214,0.2980206471839985,0.04990771098814761,0.37264829443441033,-0.3618911169814526,rsi2=20.0|H10|F50.0,False,False +50.0,rsi2,20.0,20,0.02572854059330416,0.24092581547931743,0.06592679614257868,0.4227877699377804,-0.4708151111611315,rsi2=20.0|H20|F50.0,False,False +50.0,down_days,2.0,5,0.010730375077300491,0.05183392612257233,0.05810224917952511,0.4941291938341844,-0.21584208309861164,down_days=2.0|H5|F50.0,False,False +50.0,down_days,2.0,10,0.038959054181860894,0.24692635235251997,0.04842391887727837,0.3745874746496353,-0.3417690711212783,down_days=2.0|H10|F50.0,False,False +50.0,down_days,2.0,20,0.010300375259660833,0.09692402514728912,0.08212420529260989,0.5075408480506023,-0.4326013305363656,down_days=2.0|H20|F50.0,False,False +50.0,down_days,3.0,5,0.0008686270014716886,0.002962387844185687,0.05341026203980559,0.7009541251737211,-0.09935364157856508,down_days=3.0|H5|F50.0,False,False +50.0,down_days,3.0,10,0.0011593040683485093,0.00575443830576318,0.06902218566673768,0.7139743838052309,-0.2703888671872092,down_days=3.0|H10|F50.0,False,False +50.0,down_days,3.0,20,0.09568850551906874,0.3556311642173294,0.028220918410425178,0.27188209175493633,-0.3174097664543525,down_days=3.0|H20|F50.0,False,False +50.0,down_days,4.0,5,0.014632400330276879,0.024422194016740582,0.02231405111586926,0.6059893584319144,-0.05595380467741995,down_days=4.0|H5|F50.0,False,False +50.0,down_days,4.0,10,0.014861318093432859,0.03937264762465245,0.022088589515130375,0.443020469802561,-0.10181279101013996,down_days=4.0|H10|F50.0,False,False +50.0,down_days,4.0,20,0.46599904258618446,0.6875389177508867,-0.0012963940959276332,0.019128509215291294,-0.22973323306902915,down_days=4.0|H20|F50.0,False,False +50.0,pullback,3.0,5,0.16429915727583325,0.27048011353584955,0.022905060638466868,0.23462632201942504,-0.44851015879850886,pullback=3.0|H5|F50.0,False,False +50.0,pullback,3.0,10,0.038210518831305426,0.08472068271403554,0.04998135357951394,0.38567642211331876,-0.4490336923220434,pullback=3.0|H10|F50.0,False,False +50.0,pullback,3.0,20,0.09715555804374344,0.2291553312433209,0.03983160887256898,0.30314387221381484,-0.5858639307058975,pullback=3.0|H20|F50.0,False,False +50.0,pullback,5.0,5,0.09054496061343285,0.11801860664280772,0.02735199785771969,0.3274713921343109,-0.336915280260233,pullback=5.0|H5|F50.0,False,False +50.0,pullback,5.0,10,0.05636860196153258,0.0850082902396397,0.03216842506824613,0.327334409860397,-0.31740976645435226,pullback=5.0|H10|F50.0,False,False +50.0,pullback,5.0,20,0.039843097705450616,0.06197648924607278,0.0454967751026818,0.3900396411057434,-0.37817811060319595,pullback=5.0|H20|F50.0,False,False +50.0,pullback,7.0,5,0.18766078583824097,0.21640219812391112,0.015199218240975476,0.22926632738139974,-0.26628923726027387,pullback=7.0|H5|F50.0,False,False +50.0,pullback,7.0,10,0.09381143497870809,0.12192674062519052,0.02225700660664276,0.2775696971597437,-0.3001935068334495,pullback=7.0|H10|F50.0,False,False +50.0,pullback,7.0,20,0.18213801908260774,0.25509859184150585,0.012573273865384316,0.16657265278850245,-0.36452835089697966,pullback=7.0|H20|F50.0,False,False +100.0,vix_spike,1.05,5,0.03162257549926164,0.2785903218301512,0.05281777244143582,0.3999441818197166,-0.3934289393058763,vix_spike=1.05|H5|F100.0,False,False +100.0,vix_spike,1.05,10,0.00824416400562302,0.16349738080439857,0.07722039010353332,0.5057991638267096,-0.500009212332034,vix_spike=1.05|H10|F100.0,False,False +100.0,vix_spike,1.05,20,0.013449754211634225,0.21097855959591538,0.07589794401331806,0.47373634673544024,-0.5096685492633304,vix_spike=1.05|H20|F100.0,False,False +100.0,vix_spike,1.08,5,0.051879006215892406,0.2545223929065965,0.037877461144127045,0.33552182457246327,-0.3826467709942136,vix_spike=1.08|H5|F100.0,False,False +100.0,vix_spike,1.08,10,0.011210922217712966,0.13416347332007464,0.06776258672380231,0.48317659700369897,-0.46761127738029984,vix_spike=1.08|H10|F100.0,False,False +100.0,vix_spike,1.08,20,0.01112584565264542,0.1615669287691902,0.07716518970202912,0.4926918274147296,-0.5084463581081783,vix_spike=1.08|H20|F100.0,False,False +100.0,vix_spike,1.1,5,0.01728829927014547,0.08611336219141535,0.04562302678663799,0.4470113929048279,-0.26220952742689374,vix_spike=1.1|H5|F100.0,False,False +100.0,vix_spike,1.1,10,0.007669658952477778,0.07050368323795307,0.06620212071406262,0.517928708515317,-0.32470645416997046,vix_spike=1.1|H10|F100.0,False,False +100.0,vix_spike,1.1,20,0.0076317324572160025,0.10520201565324071,0.07273129733087469,0.4963946104865935,-0.4275478618670311,vix_spike=1.1|H20|F100.0,False,False +100.0,vix_spike,1.12,5,0.03337955311747648,0.11713607562430489,0.032552670643838155,0.3703458912321156,-0.22638931202144752,vix_spike=1.12|H5|F100.0,False,False +100.0,vix_spike,1.12,10,0.03909822910801226,0.16464562605963293,0.04188572408282054,0.3781060644541164,-0.332570393130165,vix_spike=1.12|H10|F100.0,False,False +100.0,vix_spike,1.12,20,0.017100877179147732,0.12746041486054324,0.05829699795108745,0.43245401510010906,-0.42875117288560594,vix_spike=1.12|H20|F100.0,False,False +100.0,vix_spike,1.15,5,0.24666055437812667,0.4190392456133486,0.007621071129094048,0.1427791806759634,-0.18007979863631607,vix_spike=1.15|H5|F100.0,False,False +100.0,vix_spike,1.15,10,0.27055514429154304,0.5334285203676359,0.007471948321496891,0.12600173110228802,-0.25885568522932734,vix_spike=1.15|H10|F100.0,False,False +100.0,vix_spike,1.15,20,0.06948372967003377,0.2704725580541129,0.02960297023229841,0.3018575811926266,-0.24618991793669387,vix_spike=1.15|H20|F100.0,False,False +100.0,vix_cross,17.0,5,0.282558449236898,0.4737731475417754,0.005153651134605308,0.137917651403789,-0.13519229670551747,vix_cross=17.0|H5|F100.0,False,False +100.0,vix_cross,17.0,10,0.18303554937831334,0.4571121050035924,0.009791535165108556,0.1918555067780301,-0.14626085729314808,vix_cross=17.0|H10|F100.0,False,False +100.0,vix_cross,17.0,20,0.3994858820916899,0.7535881525817587,0.0014676355356439963,0.057089819207714096,-0.3241840240804208,vix_cross=17.0|H20|F100.0,False,False +100.0,vix_cross,18.0,5,0.18924975018561663,0.33193038952797654,0.009401847350848369,0.21626680807555906,-0.13627998422176035,vix_cross=18.0|H5|F100.0,False,False +100.0,vix_cross,18.0,10,0.25292422983560714,0.4889979202968297,0.008533022653527622,0.15879034059029473,-0.20497386250534344,vix_cross=18.0|H10|F100.0,False,False +100.0,vix_cross,18.0,20,0.5672917604407743,0.8539734261737737,-0.007245679591807885,-0.03691849683989663,-0.33563985966111853,vix_cross=18.0|H20|F100.0,False,False +100.0,vix_cross,19.0,5,0.48341350691012314,0.6251851205601691,-0.0007435722239288456,0.009476438162150623,-0.16552492038287525,vix_cross=19.0|H5|F100.0,False,False +100.0,vix_cross,19.0,10,0.3654332917620051,0.5801992778574225,0.0030323449181319795,0.07892753543913274,-0.17909061892971345,vix_cross=19.0|H10|F100.0,False,False +100.0,vix_cross,19.0,20,0.6418574431881411,0.8677100782606608,-0.010954225673984852,-0.0831439843491573,-0.42780468623766976,vix_cross=19.0|H20|F100.0,False,False +100.0,vix_cross,20.0,5,0.46850536412809063,0.6199849726914132,-0.0007218274251947765,0.017100150641451442,-0.17845475617335438,vix_cross=20.0|H5|F100.0,False,False +100.0,vix_cross,20.0,10,0.24741322383550954,0.4248509013588012,0.009751265775029383,0.16377046974133389,-0.23977504302118757,vix_cross=20.0|H10|F100.0,False,False +100.0,vix_cross,20.0,20,0.34961764752545743,0.6144009959826425,0.0039042573442791273,0.08919903725716277,-0.41163109554645494,vix_cross=20.0|H20|F100.0,False,False +100.0,vix_cross,22.0,5,0.43737740993809426,0.553223827042653,3.624198461604777e-05,0.035284185402412904,-0.2643056618979106,vix_cross=22.0|H5|F100.0,False,False +100.0,vix_cross,22.0,10,0.6740053023118271,0.826730463093318,-0.014148056573686563,-0.09354766672827182,-0.43887792220523514,vix_cross=22.0|H10|F100.0,False,False +100.0,vix_cross,22.0,20,0.34978281159630314,0.5478797259852126,0.0036604496430860944,0.09297562580102826,-0.5098423512811117,vix_cross=22.0|H20|F100.0,False,False +100.0,vix_cross,25.0,5,0.8652460181503414,0.900304131548474,-0.02235676517133811,-0.2810026514714476,-0.45249666105440667,vix_cross=25.0|H5|F100.0,False,False +100.0,vix_cross,25.0,10,0.49224294868942087,0.5989925872471671,-0.004851738355385216,0.00414251942210956,-0.5015803666996647,vix_cross=25.0|H10|F100.0,False,False +100.0,vix_cross,25.0,20,0.24385495931923573,0.38476465051619896,0.009520915847839095,0.13841893207988334,-0.3895872152377482,vix_cross=25.0|H20|F100.0,False,False +100.0,rsi2,5.0,5,0.1335790913411375,0.42838405193962686,0.022879189564958713,0.23107510221232333,-0.26946431818181793,rsi2=5.0|H5|F100.0,False,False +100.0,rsi2,5.0,10,0.10974846432651053,0.5351902731217828,0.028739448967871617,0.25283394285967664,-0.43255925297675735,rsi2=5.0|H10|F100.0,False,False +100.0,rsi2,5.0,20,0.012834611826805821,0.15309687841022745,0.07794332840815099,0.4938436333123085,-0.5012299704108705,rsi2=5.0|H20|F100.0,False,False +100.0,rsi2,10.0,5,0.11211120497125493,0.3934564633108142,0.026606984670332068,0.2547994811704666,-0.2997043572984748,rsi2=10.0|H5|F100.0,False,False +100.0,rsi2,10.0,10,0.0887071431761708,0.48239950178840374,0.03408209887514091,0.28281391440575665,-0.43255925297675735,rsi2=10.0|H10|F100.0,False,False +100.0,rsi2,10.0,20,0.012898971779002278,0.15709882030252337,0.07804023865736709,0.4924923605724907,-0.5012299704108705,rsi2=10.0|H20|F100.0,False,False +100.0,rsi2,15.0,5,0.05824581374153365,0.26786707437537727,0.03816423328496743,0.3305802479814404,-0.29970435729847467,rsi2=15.0|H5|F100.0,False,False +100.0,rsi2,15.0,10,0.08926232353657552,0.4848577072501425,0.03492199126973272,0.2869385082040893,-0.4325592529767578,rsi2=15.0|H10|F100.0,False,False +100.0,rsi2,15.0,20,0.009816613503607404,0.14798030834349826,0.08013015965861303,0.5011083661198207,-0.5012299704108707,rsi2=15.0|H20|F100.0,False,False +100.0,rsi2,20.0,5,0.08523736669606312,0.3681672706324707,0.031971760135681704,0.2856174868545125,-0.2997043572984749,rsi2=20.0|H5|F100.0,False,False +100.0,rsi2,20.0,10,0.09020800757374982,0.5101625604934367,0.03422291466499705,0.2820530120139712,-0.44954973110026764,rsi2=20.0|H10|F100.0,False,False +100.0,rsi2,20.0,20,0.0077035959171288795,0.12824187934802506,0.08434917381569496,0.5207460056984712,-0.5012299704108707,rsi2=20.0|H20|F100.0,False,False +100.0,down_days,2.0,5,0.10813041986536273,0.3511647979614423,0.026313087581619543,0.25660539711789526,-0.26946431818181804,down_days=2.0|H5|F100.0,False,False +100.0,down_days,2.0,10,0.14051270397047272,0.5901625797016119,0.0226462364532789,0.21812283528124116,-0.4325592529767571,down_days=2.0|H10|F100.0,False,False +100.0,down_days,2.0,20,0.010840523522276276,0.12598517428978603,0.08074350730661384,0.5085903108009437,-0.5012299704108705,down_days=2.0|H20|F100.0,False,False +100.0,down_days,3.0,5,0.007065039604600188,0.0213553851640484,0.04253535037399647,0.5260838095177494,-0.16016389123287644,down_days=3.0|H5|F100.0,False,False +100.0,down_days,3.0,10,0.00462305764119685,0.02238288560948374,0.063539104989907,0.604460704379602,-0.3001935068334496,down_days=3.0|H10|F100.0,False,False +100.0,down_days,3.0,20,0.04653712026864504,0.24384853696292666,0.04300792930615316,0.3675668568807289,-0.3246579754640849,down_days=3.0|H20|F100.0,False,False +100.0,down_days,4.0,5,0.009985400469915001,0.029134826818940043,0.021927074900612187,0.49189646913598467,-0.06349487419695166,down_days=4.0|H5|F100.0,False,False +100.0,down_days,4.0,10,0.013114634351503562,0.050931593443017585,0.029865798740614125,0.501438548453988,-0.1216524664420886,down_days=4.0|H10|F100.0,False,False +100.0,down_days,4.0,20,0.32626673623473557,0.6129301152179327,0.005671875595755216,0.1090816837574057,-0.24500733002414843,down_days=4.0|H20|F100.0,False,False +100.0,pullback,3.0,5,0.03544116122280814,0.09330338234599826,0.04442185435843404,0.39032206308344575,-0.4250357884574907,pullback=3.0|H5|F100.0,False,False +100.0,pullback,3.0,10,0.020899660828588438,0.07894384988327278,0.05524765704586532,0.4256048301544215,-0.5073941310139259,pullback=3.0|H10|F100.0,False,False +100.0,pullback,3.0,20,0.017539910187831683,0.08516025059155603,0.06825811162471007,0.4613428772455652,-0.5084874426929893,pullback=3.0|H20|F100.0,False,False +100.0,pullback,5.0,5,0.07255384671123406,0.11653684227412053,0.02550337182784146,0.2935591209057109,-0.3267743015086061,pullback=5.0|H5|F100.0,False,False +100.0,pullback,5.0,10,0.09252399908246399,0.1678450096574311,0.026210578869479972,0.2739374622612479,-0.4204460391039705,pullback=5.0|H10|F100.0,False,False +100.0,pullback,5.0,20,0.04134867943301516,0.08874425584616373,0.047512928654837916,0.39341107919860674,-0.4895253780381654,pullback=5.0|H20|F100.0,False,False +100.0,pullback,7.0,5,0.2941573815279796,0.3615048978138394,0.004528811849949799,0.09494588285046149,-0.26598173515981705,pullback=7.0|H5|F100.0,False,False +100.0,pullback,7.0,10,0.36332368267704307,0.45547529729680303,0.0018037685298830652,0.06799256478398849,-0.3871656110112949,pullback=7.0|H10|F100.0,False,False +100.0,pullback,7.0,20,0.3023592452237763,0.41285497283712325,0.0049897884954783756,0.10133883550384319,-0.4728621406213638,pullback=7.0|H20|F100.0,False,False +200.0,vix_spike,1.05,5,0.08458847385943064,0.5381192020404051,0.03188433179989514,0.27835854214308275,-0.35766130734284785,vix_spike=1.05|H5|F200.0,False,False +200.0,vix_spike,1.05,10,0.08558829064495901,0.6040989276969813,0.033924332851026806,0.27854018268277725,-0.535866719531539,vix_spike=1.05|H10|F200.0,False,False +200.0,vix_spike,1.05,20,0.03354840104580592,0.4716811809789316,0.050716522592828994,0.35747938883735586,-0.47222676745260883,vix_spike=1.05|H20|F200.0,False,False +200.0,vix_spike,1.08,5,0.11223090804567548,0.46408896972067926,0.024558947803197784,0.24463557695289737,-0.4089192003069757,vix_spike=1.08|H5|F200.0,False,False +200.0,vix_spike,1.08,10,0.018511907629985804,0.2652814479439943,0.054495254479170585,0.41223055396868563,-0.31826450033826703,vix_spike=1.08|H10|F200.0,False,False +200.0,vix_spike,1.08,20,0.061792198670830016,0.5304725176080096,0.04001653308325426,0.30786116225251553,-0.5039476514771157,vix_spike=1.08|H20|F200.0,False,False +200.0,vix_spike,1.1,5,0.00920650989429476,0.08106366235279032,0.04817523696738446,0.45619891844382476,-0.2835333093452964,vix_spike=1.1|H5|F200.0,False,False +200.0,vix_spike,1.1,10,0.007157756464143174,0.11687129247104919,0.06048945281393148,0.47827121701224257,-0.31867854527577255,vix_spike=1.1|H10|F200.0,False,False +200.0,vix_spike,1.1,20,0.0243997827249784,0.3377874184443562,0.049359199794641206,0.3710423271433096,-0.3970098790254898,vix_spike=1.1|H20|F200.0,False,False +200.0,vix_spike,1.12,5,0.01810214265326211,0.08915246425387176,0.03894534196149446,0.4132827202497332,-0.24394151079341897,vix_spike=1.12|H5|F200.0,False,False +200.0,vix_spike,1.12,10,0.013925235589981683,0.10771190487844182,0.05196336562639381,0.4455603165209534,-0.2981649411561862,vix_spike=1.12|H10|F200.0,False,False +200.0,vix_spike,1.12,20,0.03375298146131438,0.2911873343182647,0.044037612337248566,0.35248809746900817,-0.37405469039256733,vix_spike=1.12|H20|F200.0,False,False +200.0,vix_spike,1.15,5,0.08587544031884031,0.1983362777077585,0.019444798411803577,0.29399966999030014,-0.20054604982616886,vix_spike=1.15|H5|F200.0,False,False +200.0,vix_spike,1.15,10,0.05096544956443737,0.19497993186424795,0.028602270479603398,0.3325978393790604,-0.2461899179366941,vix_spike=1.15|H10|F200.0,False,False +200.0,vix_spike,1.15,20,0.08811956052139701,0.3934723887659666,0.024981102947759792,0.2594624434027295,-0.29835873388042233,vix_spike=1.15|H20|F200.0,False,False +200.0,vix_cross,17.0,5,0.23500495183567038,0.4361847200064614,0.007245311777566599,0.16345855924857994,-0.15952654804373334,vix_cross=17.0|H5|F200.0,False,False +200.0,vix_cross,17.0,10,0.17398639431118273,0.49026828021404706,0.010661603326503899,0.18576670447705637,-0.17070323251390207,vix_cross=17.0|H10|F200.0,False,False +200.0,vix_cross,17.0,20,0.08365753777112374,0.4141137405977448,0.02179681159833713,0.2944171737760748,-0.28944123242572073,vix_cross=17.0|H20|F200.0,False,False +200.0,vix_cross,18.0,5,0.12788907216739595,0.2580973956437701,0.013312727743874708,0.2659152204296021,-0.13627998422176035,vix_cross=18.0|H5|F200.0,False,False +200.0,vix_cross,18.0,10,0.25283853047374816,0.5079693777573866,0.008999621601308405,0.1565086596699654,-0.25008168952106324,vix_cross=18.0|H10|F200.0,False,False +200.0,vix_cross,18.0,20,0.3287462712293519,0.6983145159150869,0.004558041776323796,0.09554972038350898,-0.3119447002472917,vix_cross=18.0|H20|F200.0,False,False +200.0,vix_cross,19.0,5,0.26883332207321764,0.4232773000721115,0.006096547505329619,0.135939327773965,-0.1712723861522839,vix_cross=19.0|H5|F200.0,False,False +200.0,vix_cross,19.0,10,0.28283383499623505,0.5161886271059256,0.007093811418517504,0.13086142787937388,-0.19104889500371514,vix_cross=19.0|H10|F200.0,False,False +200.0,vix_cross,19.0,20,0.3644051845268006,0.6975742274655226,0.0025060669121765855,0.07442490067419633,-0.3696943146813779,vix_cross=19.0|H20|F200.0,False,False +200.0,vix_cross,20.0,5,0.17220369982728867,0.2925017354352206,0.01133543408219606,0.20724752212803088,-0.16557782207418015,vix_cross=20.0|H5|F200.0,False,False +200.0,vix_cross,20.0,10,0.08796546246877016,0.21780464252877185,0.022745832467286897,0.30974859023297496,-0.23977504302118757,vix_cross=20.0|H10|F200.0,False,False +200.0,vix_cross,20.0,20,0.12701096584397703,0.3743542205599768,0.020425936931547373,0.24807083962241322,-0.36498723792251364,vix_cross=20.0|H20|F200.0,False,False +200.0,vix_cross,22.0,5,0.5686270672513004,0.685271208117573,-0.004291457644623464,-0.03577107966743543,-0.23418866244242398,vix_cross=22.0|H5|F200.0,False,False +200.0,vix_cross,22.0,10,0.33133748532534124,0.50958930485903,0.003277830784163882,0.08189945004553505,-0.26526958923305977,vix_cross=22.0|H10|F200.0,False,False +200.0,vix_cross,22.0,20,0.39830322454254125,0.615284571474411,0.00011929676875732653,0.060983618435353805,-0.4458725618575896,vix_cross=22.0|H20|F200.0,False,False +200.0,vix_cross,25.0,5,0.9149875202715212,0.9414462086553144,-0.025637242155159168,-0.34542341890989514,-0.47361111194938377,vix_cross=25.0|H5|F200.0,False,False +200.0,vix_cross,25.0,10,0.46249958503635646,0.575088215077938,-0.0027989066324007883,0.01989616257237771,-0.43050679772499223,vix_cross=25.0|H10|F200.0,False,False +200.0,vix_cross,25.0,20,0.3023903078240801,0.485907040053239,0.004403476036386911,0.09542081842667115,-0.3361393665999639,vix_cross=25.0|H20|F200.0,False,False +200.0,rsi2,5.0,5,0.22013977531177448,0.6259540798124849,0.010757066894711231,0.1462954523262906,-0.34214948247572363,rsi2=5.0|H5|F200.0,False,False +200.0,rsi2,5.0,10,0.10875393409736847,0.5812179936247303,0.026499540090944906,0.23997299253735818,-0.3712595863550048,rsi2=5.0|H10|F200.0,False,False +200.0,rsi2,5.0,20,0.014980936922448994,0.3011307034506203,0.06200869885903981,0.42179985663330627,-0.3646496815286626,rsi2=5.0|H20|F200.0,False,False +200.0,rsi2,10.0,5,0.2086029719266942,0.622287665076653,0.0121007971597622,0.15533401840215924,-0.37902572306066906,rsi2=10.0|H5|F200.0,False,False +200.0,rsi2,10.0,10,0.10136694970431878,0.5615519704285242,0.02927824012245983,0.25495025416195966,-0.3646496815286622,rsi2=10.0|H10|F200.0,False,False +200.0,rsi2,10.0,20,0.01616765752996294,0.32087074830940454,0.06065911934566204,0.41239551206546604,-0.36510263649492025,rsi2=10.0|H20|F200.0,False,False +200.0,rsi2,15.0,5,0.14409037871698738,0.5377628864804632,0.019383875437670506,0.203753552104246,-0.34586054129896004,rsi2=15.0|H5|F200.0,False,False +200.0,rsi2,15.0,10,0.12832871779591618,0.6254898366155035,0.024336654595776608,0.22622640814960784,-0.36953700987926463,rsi2=15.0|H10|F200.0,False,False +200.0,rsi2,15.0,20,0.017855842229764492,0.333515745168237,0.059376821841778726,0.4050529308611155,-0.37767472418348713,rsi2=15.0|H20|F200.0,False,False +200.0,rsi2,20.0,5,0.14868249763957478,0.5724348682480171,0.0186970665991677,0.1986106803668439,-0.33884051522303615,rsi2=20.0|H5|F200.0,False,False +200.0,rsi2,20.0,10,0.11101569798465508,0.6012342251849253,0.027534584258208206,0.24439882444755665,-0.36953700987926463,rsi2=20.0|H10|F200.0,False,False +200.0,rsi2,20.0,20,0.015479054968370707,0.3156672525002071,0.061703381145572056,0.41675562589866033,-0.37767472418348746,rsi2=20.0|H20|F200.0,False,False +200.0,down_days,2.0,5,0.13799959959993474,0.4748872821906225,0.019000370325624738,0.20420056160073596,-0.33344732111384523,down_days=2.0|H5|F200.0,False,False +200.0,down_days,2.0,10,0.09360940204037577,0.5228049798277176,0.028969316891070296,0.2559224516254325,-0.3646496815286622,down_days=2.0|H10|F200.0,False,False +200.0,down_days,2.0,20,0.010520392921814524,0.2336222971147439,0.06721087897523681,0.4508411776443816,-0.3646496815286626,down_days=2.0|H20|F200.0,False,False +200.0,down_days,3.0,5,0.015877522673991906,0.04895141086099168,0.04125838232445411,0.44945892089851125,-0.26598173515981705,down_days=3.0|H5|F200.0,False,False +200.0,down_days,3.0,10,0.004001003480119735,0.03212169516953349,0.06379612900820719,0.5730679730586814,-0.3001935068334495,down_days=3.0|H10|F200.0,False,False +200.0,down_days,3.0,20,0.008352465318124036,0.1191543558041325,0.06550941901478002,0.5117101106148555,-0.3227176220806789,down_days=3.0|H20|F200.0,False,False +200.0,down_days,4.0,5,0.04908125972933508,0.10755430539016211,0.018544104879174794,0.3229079179109799,-0.12621497856250585,down_days=4.0|H5|F200.0,False,False +200.0,down_days,4.0,10,0.022473691365086847,0.08683320513398293,0.02979479052903522,0.4037767475809072,-0.14978155839678864,down_days=4.0|H10|F200.0,False,False +200.0,down_days,4.0,20,0.162640480696669,0.44384816555504225,0.01619010539925414,0.20564920853658342,-0.29222410738057336,down_days=4.0|H20|F200.0,False,False +200.0,pullback,3.0,5,0.011628452124871017,0.04390129395609931,0.05645848025926825,0.4571588413826526,-0.32002238636363645,pullback=3.0|H5|F200.0,False,False +200.0,pullback,3.0,10,0.02232691906779312,0.11383026185134953,0.05133104712583236,0.3950520524716593,-0.3646496815286626,pullback=3.0|H10|F200.0,False,False +200.0,pullback,3.0,20,0.02150942169196609,0.17808505991285406,0.05376232896722977,0.39351180612038317,-0.39525007204373164,pullback=3.0|H20|F200.0,False,False +200.0,pullback,5.0,5,0.015322458677549564,0.03132300245420504,0.04039008742132988,0.4034561101886273,-0.32002238636363645,pullback=5.0|H5|F200.0,False,False +200.0,pullback,5.0,10,0.017783844651431093,0.04423504723136921,0.04304963236866177,0.3915271868824861,-0.3646496815286624,pullback=5.0|H10|F200.0,False,False +200.0,pullback,5.0,20,0.015437249828530638,0.05588934590474086,0.04784685689944501,0.3997149272040639,-0.3646496815286623,pullback=5.0|H20|F200.0,False,False +200.0,pullback,7.0,5,0.0979024335536864,0.1392245029536006,0.017651933726425817,0.2275421564836367,-0.3167808219178082,pullback=7.0|H5|F200.0,False,False +200.0,pullback,7.0,10,0.023813660197096034,0.04087634608377302,0.03290011293176587,0.3447818405649843,-0.34862490488307896,pullback=7.0|H10|F200.0,False,False +200.0,pullback,7.0,20,0.060589108962013506,0.11892916160699205,0.02634145989585135,0.27478995721603006,-0.3646496815286624,pullback=7.0|H20|F200.0,False,False diff --git a/pipeline_oos_survivors.csv b/pipeline_oos_survivors.csv new file mode 100644 index 0000000..dbd7dd3 --- /dev/null +++ b/pipeline_oos_survivors.csv @@ -0,0 +1,2 @@ +name,is_sharpe,is_p,oos_cagr,oos_sharpe,oos_maxdd,oos_p,by,live +down_days=3.0|H5|Fnan,0.7161580962126374,0.0001320479221337519,0.060870904639343415,0.4850645183649593,-0.20296100686264607,0.29897054474261964,False,False diff --git a/strategy_pipeline.py b/strategy_pipeline.py new file mode 100644 index 0000000..5d647ec --- /dev/null +++ b/strategy_pipeline.py @@ -0,0 +1,321 @@ +#!/usr/bin/env python3 +""" +Multiple-testing-aware strategy discovery pipeline for QQQ. + +Guards against data-mining bias (Harvey & Liu, 2014; "...and the Cross-Section +of Expected Returns"). Steps: + + 1. Enumerate a LARGE grid of candidate long/flat timing strategies + (trend filter x entry trigger x holding period). + 2. In-sample (IS) test: for each candidate compute the daily net-of-cost P&L + and a HAC (Newey-West) t-statistic for H0: mean daily return <= 0. + HAC standard errors account for the autocorrelation induced by + overlapping holding windows. + 3. Multiple-testing correction on the IS one-sided p-values: + Benjamini-Hochberg FDR (assumes positive dependence) AND the more + conservative Benjamini-Yekutieli FDR (valid under arbitrary dependence). + 4. Out-of-sample (OOS) confirmation on a held-out period the search never + touched: survivors must stay profitable and significant there. + 5. Strategies passing BOTH gates are flagged 'LIVE-ELIGIBLE'. + +Educational research tooling, not investment advice. Backtests overstate +live performance (slippage, regime change, survivorship). +""" + +import itertools +import sys +import numpy as np +import pandas as pd +import requests + +CA_BUNDLE = "/root/.ccr/ca-bundle.crt" +HEADERS = {"User-Agent": "Mozilla/5.0"} +COST = 0.0002 +TD = 252 +IS_END = pd.Timestamp("2016-12-31") # in-sample: start .. 2016 +OOS_START = pd.Timestamp("2017-01-01") # out-of-sample: 2017 .. now +FDR_Q = 0.10 +OOS_ALPHA = 0.05 + + +# ---------------- data ---------------- +def fetch_yahoo(symbol): + url = f"https://query1.finance.yahoo.com/v8/finance/chart/{symbol}" + params = {"period1": 0, "period2": 9999999999, "interval": "1d"} + r = requests.get(url, params=params, headers=HEADERS, timeout=60, verify=CA_BUNDLE) + r.raise_for_status() + res = r.json()["chart"]["result"][0] + q = res["indicators"]["quote"][0] + df = pd.DataFrame( + {"open": q["open"], "high": q["high"], "low": q["low"], "close": q["close"]}, + index=pd.to_datetime(res["timestamp"], unit="s").normalize(), + ).dropna(subset=["high", "close"]) + df.index.name = "date" + return df + + +def rsi(series, n): + delta = series.diff() + up = delta.clip(lower=0).rolling(n).mean() + down = (-delta.clip(upper=0)).rolling(n).mean() + rs = up / down.replace(0, np.nan) + return 100 - 100 / (1 + rs) + + +def load(): + vix = fetch_yahoo("%5EVIX") + qqq = fetch_yahoo("QQQ") + d = pd.DataFrame({ + "vix_high": vix["high"], "vix_close": vix["close"], "close": qqq["close"], + }).dropna().sort_index() + d["ret"] = d["close"].pct_change() + for n in (50, 100, 200): + d[f"sma{n}"] = d["close"].rolling(n).mean() + d["rsi2"] = rsi(d["close"], 2) + d["down"] = d["close"].diff() < 0 + d["roll_max20"] = d["close"].rolling(20).max() + return d + + +# ---------------- candidate signals ---------------- +def trend_ok(d, filt): + if filt is None or (isinstance(filt, float) and pd.isna(filt)): + return pd.Series(True, index=d.index) + return d["close"] > d[f"sma{int(filt)}"] + + +def entry_signal(d, kind, param): + if kind == "vix_spike": + return d["vix_high"] >= param * d["vix_close"].shift(1) + if kind == "vix_cross": + return (d["vix_high"].shift(1) < param) & (d["vix_high"] >= param) + if kind == "rsi2": + return d["rsi2"] < param + if kind == "down_days": + s = d["down"] + cond = s.copy() + for k in range(1, int(param)): + cond = cond & s.shift(k) + return cond + if kind == "pullback": + return d["close"] <= d["roll_max20"] * (1 - param / 100.0) + raise ValueError(kind) + + +def position(d, filt, kind, param, hold): + sig = (entry_signal(d, kind, param) & trend_ok(d, filt)).fillna(False).values + pos = np.zeros(len(d)) + remaining = 0 + for i in range(len(d)): + if sig[i]: + remaining = hold + if remaining > 0: + pos[i] = 1.0 + remaining -= 1 + return pd.Series(pos, index=d.index) + + +def candidates(): + filters = [None, 50, 100, 200] + triggers = ( + [("vix_spike", k) for k in (1.05, 1.08, 1.10, 1.12, 1.15)] + + [("vix_cross", L) for L in (17, 18, 19, 20, 22, 25)] + + [("rsi2", th) for th in (5, 10, 15, 20)] + + [("down_days", n) for n in (2, 3, 4)] + + [("pullback", x) for x in (3, 5, 7)] + ) + holds = [5, 10, 20] + out = [] + for filt, (kind, param), hold in itertools.product(filters, triggers, holds): + out.append({"filt": filt, "kind": kind, "param": param, "hold": hold}) + return out + + +# ---------------- stats ---------------- +def hac_tstat(x, lag): + """Newey-West HAC t-stat for H0: mean(x) <= 0 (one-sided).""" + x = np.asarray(x, float) + n = len(x) + if n < 30: + return np.nan, np.nan + xbar = x.mean() + xc = x - xbar + gamma0 = np.dot(xc, xc) / n + lrv = gamma0 + for l in range(1, lag + 1): + w = 1 - l / (lag + 1) + g = np.dot(xc[l:], xc[:-l]) / n + lrv += 2 * w * g + if lrv <= 0: + return np.nan, np.nan + se = np.sqrt(lrv / n) + t = xbar / se + return t, se + + +def norm_sf(z): + # one-sided upper-tail p-value via erfc (no scipy dependency) + from math import erfc, sqrt + return 0.5 * erfc(z / sqrt(2)) + + +def metrics(pnl): + pnl = pnl.dropna() + n = len(pnl) + if n == 0: + return {} + eq = (1 + pnl).cumprod() + yrs = n / TD + total = eq.iloc[-1] - 1 + cagr = eq.iloc[-1] ** (1 / yrs) - 1 if yrs > 0 else np.nan + vol = pnl.std() * np.sqrt(TD) + sharpe = (pnl.mean() * TD) / vol if vol > 0 else np.nan + dd = (eq / eq.cummax() - 1).min() + return {"total": total, "cagr": cagr, "sharpe": sharpe, "maxdd": dd} + + +def strat_pnl(d, spec): + pos = position(d, spec["filt"], spec["kind"], spec["param"], spec["hold"]) + trades = pos.diff().abs().fillna(0.0) + held = pos.shift(1).fillna(0.0) + ret = d["ret"].fillna(0.0) + pnl = held * ret - trades * COST + # Timing-alpha (active) return: strips the passive equity premium by + # benchmarking against a constant-exposure position at the strategy's own + # average exposure. mean>0 <=> the strategy is invested MORE on up days than + # its average -- i.e. genuine market-timing skill, not just being long. + active = (held - held.mean()) * ret + return pnl, active, pos + + +# ---------------- FDR ---------------- +def bh_reject(pvals, q): + p = np.asarray(pvals, float) + m = len(p) + order = np.argsort(p) + thresh = q * (np.arange(1, m + 1)) / m + passed = p[order] <= thresh + kmax = np.where(passed)[0].max() + 1 if passed.any() else 0 + rej = np.zeros(m, bool) + if kmax > 0: + rej[order[:kmax]] = True + return rej + + +def by_reject(pvals, q): + m = len(pvals) + c_m = np.sum(1.0 / np.arange(1, m + 1)) # harmonic number + return bh_reject(pvals, q / c_m) + + +# ---------------- run ---------------- +def main(): + print("Loading data ...", file=sys.stderr) + d = load() + d_is = d[d.index <= IS_END] + d_oos = d[d.index >= OOS_START] + print(f"IS : {d_is.index[0].date()} -> {d_is.index[-1].date()} ({len(d_is)} days)") + print(f"OOS: {d_oos.index[0].date()} -> {d_oos.index[-1].date()} ({len(d_oos)} days)\n") + + specs = candidates() + print(f"Candidate strategies: {len(specs)}\n") + + rows = [] + bh_is = metrics(d_is["ret"]) + bh_oos = metrics(d_oos["ret"]) + + for i, spec in enumerate(specs): + pnl_is, active_is, pos_is = strat_pnl(d_is, spec) + lag = spec["hold"] + 5 + t_ret, _ = hac_tstat(pnl_is.fillna(0.0).values, lag) + t_a, _ = hac_tstat(active_is.fillna(0.0).values, lag) + if np.isnan(t_ret) or np.isnan(t_a): + continue + m_is = metrics(pnl_is) + rows.append({ + **spec, + "p_ret": norm_sf(t_ret), # raw return > 0 (captures beta) + "p": norm_sf(t_a), # timing-alpha > 0 (skill) -- FDR gate + "is_cagr": m_is["cagr"], "is_sharpe": m_is["sharpe"], + "is_maxdd": m_is["maxdd"], + }) + + res = pd.DataFrame(rows) + res["name"] = res.apply( + lambda r: f"{r['kind']}={r['param']}|H{r['hold']}|" + f"F{r['filt'] if r['filt'] else '-'}", axis=1) + + # FDR correction on IS p-values + res["bh"] = bh_reject(res["p"].values, FDR_Q) + res["by"] = by_reject(res["p"].values, FDR_Q) + n_beta = int((res["p_ret"] < 0.05).sum()) + n_naive = int((res["p"] < 0.05).sum()) + print("IS gate = market-timing ALPHA (raw-return premium stripped out)") + print(f" would pass on raw return p<0.05 (beta-driven) : {n_beta}/{len(res)}") + print(f" significant timing-alpha at naive p<0.05 : {n_naive}/{len(res)}") + print(f" survive Benjamini-Hochberg FDR<{FDR_Q} (pos. dep.) : {int(res['bh'].sum())}") + print(f" survive Benjamini-Yekutieli FDR<{FDR_Q} (arb. dep.): {int(res['by'].sum())}\n") + + survivors = res[res["bh"]].copy() + + # OOS confirmation on BH survivors + oos_rec = [] + for _, r in survivors.iterrows(): + spec = {"filt": r["filt"], "kind": r["kind"], + "param": r["param"], "hold": r["hold"]} + pnl_oos, active_oos, _ = strat_pnl(d_oos, spec) + t_o, _ = hac_tstat(active_oos.fillna(0.0).values, spec["hold"] + 5) + p_o = norm_sf(t_o) if not np.isnan(t_o) else np.nan + m_o = metrics(pnl_oos) + oos_rec.append({ + "name": r["name"], "is_sharpe": r["is_sharpe"], "is_p": r["p"], + "oos_cagr": m_o["cagr"], "oos_sharpe": m_o["sharpe"], + "oos_maxdd": m_o["maxdd"], "oos_p": p_o, + "by": bool(r["by"]), + # OOS gate is also on timing-alpha, not raw return. + "live": (not np.isnan(p_o)) and (p_o < OOS_ALPHA) and (m_o["cagr"] > 0), + }) + oos = pd.DataFrame(oos_rec).sort_values("oos_sharpe", ascending=False) + + pd.set_option("display.width", 200) + print("=" * 100) + print(f"BENCHMARK Buy&Hold IS: CAGR {bh_is['cagr']*100:.1f}% Sharpe " + f"{bh_is['sharpe']:.2f} MaxDD {bh_is['maxdd']*100:.1f}% | " + f"OOS: CAGR {bh_oos['cagr']*100:.1f}% Sharpe {bh_oos['sharpe']:.2f} " + f"MaxDD {bh_oos['maxdd']*100:.1f}%") + print("=" * 100) + + if oos.empty: + print("No strategies survived the FDR gate.") + else: + print(f"\nBH-FDR survivors carried to OOS ({len(oos)}):\n") + show = oos.copy() + for c in ["is_sharpe", "oos_sharpe"]: + show[c] = show[c].map(lambda v: f"{v:.2f}") + for c in ["oos_cagr", "oos_maxdd"]: + show[c] = show[c].map(lambda v: f"{v*100:+.1f}%") + for c in ["is_p", "oos_p"]: + show[c] = show[c].map(lambda v: f"{v:.3f}" if pd.notnull(v) else "na") + print(show[["name", "is_sharpe", "is_p", "oos_cagr", "oos_sharpe", + "oos_maxdd", "oos_p", "by", "live"]].to_string(index=False)) + + live = oos[oos["live"]] + print("\n" + "=" * 100) + print(f"LIVE-ELIGIBLE (passed FDR IS-gate AND OOS p<{OOS_ALPHA} with " + f"positive OOS CAGR): {len(live)}") + print("=" * 100) + if not live.empty: + for _, r in live.iterrows(): + tag = " [also survives BY]" if r["by"] else "" + print(f" {r['name']:<28} OOS CAGR {r['oos_cagr']*100:+.1f}% " + f"Sharpe {r['oos_sharpe']:.2f} MaxDD {r['oos_maxdd']*100:.1f}%" + f"{tag}") + + res.to_csv("pipeline_is_results.csv", index=False) + if not oos.empty: + oos.to_csv("pipeline_oos_survivors.csv", index=False) + print("\nSaved pipeline_is_results.csv and pipeline_oos_survivors.csv") + + +if __name__ == "__main__": + main() diff --git a/vix_qqq_backtest.py b/vix_qqq_backtest.py new file mode 100644 index 0000000..7a950ae --- /dev/null +++ b/vix_qqq_backtest.py @@ -0,0 +1,182 @@ +#!/usr/bin/env python3 +""" +VIX threshold-crossing backtest on QQQ. + +Strategy / signal +----------------- +For each threshold T in {17, 18, 19, 20, 21, 22}: + A signal fires on day D when: + * VIX High on day D-1 (previous trading day) < T + * VIX High on day D (current day) >= T + On a signal, buy QQQ at day D's close. + Measure the forward return of QQQ close over the next 5 / 20 / 60 trading days. + +For each threshold and horizon we report: + sample count, mean, median, win rate, best, worst. + +Benchmark: QQQ buy & hold average forward return over the same 5/20/60-day +horizons, computed over every trading day (so the strategy's edge can be +compared against "just being in the market on a random day"). + +Data: Yahoo Finance daily OHLC (^VIX and QQQ). +""" + +import io +import json +import sys + +import numpy as np +import pandas as pd +import requests + +CA_BUNDLE = "/root/.ccr/ca-bundle.crt" +THRESHOLDS = [17, 18, 19, 20, 21, 22] +HORIZONS = [5, 20, 60] +HEADERS = {"User-Agent": "Mozilla/5.0"} + + +def fetch_yahoo(symbol): + """Return a DataFrame indexed by date with OHLC columns for a Yahoo symbol.""" + url = f"https://query1.finance.yahoo.com/v8/finance/chart/{symbol}" + params = {"period1": 0, "period2": 9999999999, "interval": "1d"} + r = requests.get(url, params=params, headers=HEADERS, + timeout=60, verify=CA_BUNDLE) + r.raise_for_status() + res = r.json()["chart"]["result"][0] + ts = res["timestamp"] + q = res["indicators"]["quote"][0] + df = pd.DataFrame({ + "open": q["open"], + "high": q["high"], + "low": q["low"], + "close": q["close"], + }, index=pd.to_datetime(ts, unit="s").normalize()) + df.index.name = "date" + df = df.dropna(subset=["high", "close"]) + return df + + +def main(): + # Optional signal-window start date (YYYY-MM-DD). Forward returns are always + # computed on the full price history; only signals/benchmark are windowed. + start = None + for a in sys.argv[1:]: + if a.startswith("--start="): + start = pd.Timestamp(a.split("=", 1)[1]) + + print("Fetching data from Yahoo Finance ...", file=sys.stderr) + vix = fetch_yahoo("%5EVIX") # ^VIX + qqq = fetch_yahoo("QQQ") + + # Align to the common trading calendar (QQQ starts 1999-03-10). + df = pd.DataFrame({ + "vix_high": vix["high"], + "qqq_close": qqq["close"], + }).dropna() + df = df.sort_index() + + df["vix_high_prev"] = df["vix_high"].shift(1) + + # Forward returns of QQQ close for each horizon. + for h in HORIZONS: + df[f"fwd_{h}"] = df["qqq_close"].shift(-h) / df["qqq_close"] - 1.0 + + # Full price history is kept for forward-return lookups above; the analysis + # window (signals + benchmark) can be restricted to a start date. + full = df + if start is not None: + df = df[df.index >= start] + + n_days = len(df) + span = f"{df.index[0].date()} to {df.index[-1].date()}" + window_note = f" [signal window >= {start.date()}]" if start is not None else "" + print(f"Aligned trading days: {n_days} ({span}){window_note}\n") + + # ---- Buy & Hold benchmark (every trading day) ---- + bh = {} + for h in HORIZONS: + s = df[f"fwd_{h}"].dropna() + bh[h] = { + "n": int(s.shape[0]), + "mean": float(s.mean()), + "median": float(s.median()), + "win": float((s > 0).mean()), + "best": float(s.max()), + "worst": float(s.min()), + } + + # ---- Strategy per threshold ---- + results = {} + for T in THRESHOLDS: + signal = (df["vix_high_prev"] < T) & (df["vix_high"] >= T) + sig = df[signal] + per_h = {} + for h in HORIZONS: + s = sig[f"fwd_{h}"].dropna() + if s.empty: + per_h[h] = None + continue + per_h[h] = { + "n": int(s.shape[0]), + "mean": float(s.mean()), + "median": float(s.median()), + "win": float((s > 0).mean()), + "best": float(s.max()), + "worst": float(s.min()), + } + results[T] = { + "total_signals": int(signal.sum()), + "horizons": per_h, + "signal_dates": [d.strftime("%Y-%m-%d") for d in sig.index], + } + + out = { + "data_span": span, + "trading_days": n_days, + "thresholds": THRESHOLDS, + "horizons": HORIZONS, + "buy_and_hold": bh, + "strategy": results, + } + + with open("vix_qqq_results.json", "w") as f: + json.dump(out, f, indent=2) + + # ---- Pretty print ---- + def pct(x): + return f"{x * 100:+6.2f}%" + + print("=" * 78) + print("QQQ BUY & HOLD BENCHMARK (average forward return over ALL trading days)") + print("=" * 78) + print(f"{'Horizon':>8} {'N':>7} {'Mean':>9} {'Median':>9} {'Win%':>7} " + f"{'Best':>9} {'Worst':>9}") + for h in HORIZONS: + b = bh[h] + print(f"{h:>6}d {b['n']:>7} {pct(b['mean']):>9} {pct(b['median']):>9} " + f"{b['win'] * 100:>6.1f}% {pct(b['best']):>9} {pct(b['worst']):>9}") + + for T in THRESHOLDS: + r = results[T] + print("\n" + "=" * 78) + print(f"THRESHOLD {T} (VIX High crosses up through {T}: " + f"prev High < {T} and today High >= {T})") + print(f"Total signal days: {r['total_signals']}") + print("=" * 78) + print(f"{'Horizon':>8} {'N':>7} {'Mean':>9} {'Median':>9} {'Win%':>7} " + f"{'Best':>9} {'Worst':>9} {' vs B&H(mean)':>14}") + for h in HORIZONS: + d = r["horizons"][h] + if d is None: + print(f"{h:>6}d - (no completed samples)") + continue + edge = d["mean"] - bh[h]["mean"] + print(f"{h:>6}d {d['n']:>7} {pct(d['mean']):>9} {pct(d['median']):>9} " + f"{d['win'] * 100:>6.1f}% {pct(d['best']):>9} {pct(d['worst']):>9} " + f"{pct(edge):>14}") + + print("\nSaved detailed results (incl. signal dates) to vix_qqq_results.json") + + +if __name__ == "__main__": + main() diff --git a/vix_qqq_results.json b/vix_qqq_results.json new file mode 100644 index 0000000..ea0bf5b --- /dev/null +++ b/vix_qqq_results.json @@ -0,0 +1,538 @@ +{ + "data_span": "2021-08-10 to 2026-08-07", + "trading_days": 1254, + "thresholds": [ + 17, + 18, + 19, + 20, + 21, + 22 + ], + "horizons": [ + 5, + 20, + 60 + ], + "buy_and_hold": { + "5": { + "n": 1249, + "mean": 0.003138296789026028, + "median": 0.0051984480660698384, + "win": 0.5748598879103283, + "best": 0.10077871682407125, + "worst": -0.11982232533480563 + }, + "20": { + "n": 1234, + "mean": 0.01202913585405011, + "median": 0.01545511618643891, + "win": 0.6191247974068071, + "best": 0.20525969712266257, + "worst": -0.15937638583593183 + }, + "60": { + "n": 1194, + "mean": 0.03836659718447432, + "median": 0.04653715628976818, + "win": 0.6758793969849246, + "best": 0.3268039045717981, + "worst": -0.24105061455776944 + } + }, + "strategy": { + "17": { + "total_signals": 52, + "horizons": { + "5": { + "n": 51, + "mean": -0.000397887254264299, + "median": 0.0029504630475947202, + "win": 0.6078431372549019, + "best": 0.03794034703293514, + "worst": -0.04930729886574403 + }, + "20": { + "n": 49, + "mean": 0.009383555926493871, + "median": 0.01501830979627572, + "win": 0.6530612244897959, + "best": 0.08957976364882358, + "worst": -0.11349610607709382 + }, + "60": { + "n": 46, + "mean": 0.028079584256733712, + "median": 0.047912148321742065, + "win": 0.6739130434782609, + "best": 0.20070137492494355, + "worst": -0.17956826849498064 + } + }, + "signal_dates": [ + "2021-08-16", + "2021-08-31", + "2021-09-03", + "2021-10-18", + "2021-10-27", + "2021-11-05", + "2023-05-02", + "2023-07-06", + "2023-08-03", + "2023-08-17", + "2023-09-21", + "2024-02-13", + "2024-04-11", + "2024-04-25", + "2024-07-19", + "2024-07-24", + "2024-08-01", + "2024-08-21", + "2024-08-28", + "2024-09-03", + "2024-09-30", + "2024-11-15", + "2024-12-18", + "2024-12-27", + "2025-01-07", + "2025-01-27", + "2025-01-31", + "2025-02-12", + "2025-02-21", + "2025-06-27", + "2025-07-07", + "2025-07-11", + "2025-07-22", + "2025-07-30", + "2025-08-20", + "2025-09-02", + "2025-09-23", + "2025-10-01", + "2025-10-03", + "2025-10-29", + "2025-12-08", + "2025-12-12", + "2026-01-14", + "2026-01-20", + "2026-01-26", + "2026-01-28", + "2026-06-05", + "2026-06-17", + "2026-07-08", + "2026-07-13", + "2026-07-16", + "2026-08-05" + ] + }, + "18": { + "total_signals": 57, + "horizons": { + "5": { + "n": 56, + "mean": 0.002526733304778989, + "median": 0.006194204073668996, + "win": 0.6071428571428571, + "best": 0.06005524439913912, + "worst": -0.06184163412063948 + }, + "20": { + "n": 54, + "mean": 0.011578655551448581, + "median": 0.014493890245094954, + "win": 0.6481481481481481, + "best": 0.11160072299361556, + "worst": -0.08747019674920486 + }, + "60": { + "n": 50, + "mean": 0.04132396163462907, + "median": 0.06108182125506367, + "win": 0.72, + "best": 0.20070137492494355, + "worst": -0.17956826849498064 + } + }, + "signal_dates": [ + "2021-08-17", + "2021-08-26", + "2021-09-07", + "2021-10-29", + "2021-11-09", + "2021-11-18", + "2021-12-31", + "2022-01-05", + "2023-04-24", + "2023-05-02", + "2023-05-10", + "2023-05-15", + "2023-05-22", + "2023-08-08", + "2023-08-17", + "2023-09-25", + "2023-10-02", + "2023-10-12", + "2024-04-12", + "2024-07-24", + "2024-07-30", + "2024-08-01", + "2024-08-22", + "2024-09-03", + "2024-09-17", + "2024-10-01", + "2024-11-20", + "2024-12-18", + "2024-12-27", + "2025-01-02", + "2025-01-07", + "2025-01-27", + "2025-02-03", + "2025-02-21", + "2025-03-26", + "2025-05-19", + "2025-06-11", + "2025-07-07", + "2025-07-16", + "2025-08-01", + "2025-09-02", + "2025-10-10", + "2025-10-31", + "2025-12-17", + "2026-01-14", + "2026-01-20", + "2026-01-29", + "2026-02-11", + "2026-05-04", + "2026-05-11", + "2026-06-05", + "2026-06-17", + "2026-06-23", + "2026-07-08", + "2026-07-17", + "2026-07-22", + "2026-08-05" + ] + }, + "19": { + "total_signals": 54, + "horizons": { + "5": { + "n": 54, + "mean": 0.005179920047556141, + "median": 0.008431420238394827, + "win": 0.6111111111111112, + "best": 0.06005524439913912, + "worst": -0.0687655588859718 + }, + "20": { + "n": 52, + "mean": 0.016763236651556733, + "median": 0.014847447458760099, + "win": 0.6923076923076923, + "best": 0.12384656729048382, + "worst": -0.14466646189504417 + }, + "60": { + "n": 49, + "mean": 0.0526922446635316, + "median": 0.07757908753862908, + "win": 0.7551020408163265, + "best": 0.21174882001450723, + "worst": -0.177732089231886 + } + }, + "signal_dates": [ + "2021-08-17", + "2021-08-26", + "2021-09-08", + "2021-11-10", + "2021-11-19", + "2021-12-27", + "2022-01-05", + "2022-01-13", + "2023-04-25", + "2023-05-02", + "2023-05-04", + "2023-05-23", + "2023-09-26", + "2023-10-03", + "2023-10-13", + "2023-10-18", + "2024-04-12", + "2024-04-19", + "2024-07-25", + "2024-08-01", + "2024-09-03", + "2024-09-18", + "2024-10-01", + "2024-12-18", + "2024-12-30", + "2025-01-02", + "2025-01-08", + "2025-01-27", + "2025-02-03", + "2025-02-21", + "2025-03-26", + "2025-05-15", + "2025-05-19", + "2025-05-21", + "2025-06-13", + "2025-07-16", + "2025-08-01", + "2025-09-02", + "2025-10-10", + "2025-10-22", + "2025-11-04", + "2025-11-13", + "2026-01-20", + "2026-01-29", + "2026-02-12", + "2026-04-16", + "2026-04-20", + "2026-05-04", + "2026-05-12", + "2026-05-15", + "2026-06-05", + "2026-06-23", + "2026-07-17", + "2026-07-22" + ] + }, + "20": { + "total_signals": 53, + "horizons": { + "5": { + "n": 53, + "mean": 0.007293232225419666, + "median": 0.00934738410944691, + "win": 0.660377358490566, + "best": 0.08397686211051614, + "worst": -0.09866931541941393 + }, + "20": { + "n": 51, + "mean": 0.016870468211586862, + "median": 0.016128753968992937, + "win": 0.6274509803921569, + "best": 0.1217066098444064, + "worst": -0.10645887101835971 + }, + "60": { + "n": 48, + "mean": 0.06360778893320072, + "median": 0.08571230647702632, + "win": 0.8333333333333334, + "best": 0.21070940407956984, + "worst": -0.2033288427237785 + } + }, + "signal_dates": [ + "2021-08-18", + "2021-09-10", + "2021-09-17", + "2021-09-28", + "2021-10-11", + "2021-11-23", + "2022-01-05", + "2022-01-13", + "2022-03-30", + "2023-01-17", + "2023-01-30", + "2023-02-08", + "2023-02-16", + "2023-03-08", + "2023-03-30", + "2023-04-04", + "2023-04-10", + "2023-05-04", + "2023-05-24", + "2023-10-03", + "2023-10-13", + "2023-10-18", + "2024-04-19", + "2024-08-02", + "2024-09-03", + "2024-10-01", + "2024-10-23", + "2024-10-29", + "2024-12-18", + "2025-01-10", + "2025-01-27", + "2025-02-03", + "2025-02-24", + "2025-03-28", + "2025-05-21", + "2025-05-29", + "2025-06-13", + "2025-08-01", + "2025-10-10", + "2025-10-22", + "2025-11-04", + "2025-11-13", + "2026-01-20", + "2026-02-03", + "2026-02-12", + "2026-02-26", + "2026-04-21", + "2026-04-23", + "2026-06-05", + "2026-06-23", + "2026-06-26", + "2026-07-23", + "2026-07-29" + ] + }, + "21": { + "total_signals": 50, + "horizons": { + "5": { + "n": 50, + "mean": 0.0025563136078792592, + "median": 0.0068010314914316305, + "win": 0.56, + "best": 0.06610940521499553, + "worst": -0.09866931541941393 + }, + "20": { + "n": 50, + "mean": 0.012299137922432953, + "median": 0.018978022799173933, + "win": 0.64, + "best": 0.1553312510788094, + "worst": -0.13595743196109733 + }, + "60": { + "n": 48, + "mean": 0.0482895516351726, + "median": 0.07565524390627876, + "win": 0.7291666666666666, + "best": 0.2126699564530663, + "worst": -0.2186928825419765 + } + }, + "signal_dates": [ + "2021-08-18", + "2021-09-10", + "2021-09-17", + "2021-09-28", + "2021-11-26", + "2022-01-06", + "2022-01-10", + "2022-01-14", + "2022-03-31", + "2022-04-05", + "2022-08-15", + "2022-08-19", + "2022-12-05", + "2023-01-19", + "2023-02-09", + "2023-02-17", + "2023-03-09", + "2023-05-04", + "2023-10-19", + "2023-10-25", + "2024-04-19", + "2024-08-02", + "2024-09-03", + "2024-09-11", + "2024-10-07", + "2024-10-16", + "2024-10-31", + "2024-12-18", + "2025-01-13", + "2025-01-27", + "2025-02-25", + "2025-02-27", + "2025-03-28", + "2025-05-21", + "2025-06-13", + "2025-06-17", + "2025-08-01", + "2025-10-10", + "2025-10-14", + "2025-10-22", + "2025-11-07", + "2025-11-13", + "2026-02-04", + "2026-02-12", + "2026-02-19", + "2026-02-27", + "2026-04-13", + "2026-04-23", + "2026-06-05", + "2026-06-09" + ] + }, + "22": { + "total_signals": 41, + "horizons": { + "5": { + "n": 41, + "mean": 0.004729890061364004, + "median": 0.00758437839065218, + "win": 0.5853658536585366, + "best": 0.06486923070532713, + "worst": -0.09866931541941393 + }, + "20": { + "n": 41, + "mean": 0.009766392712114847, + "median": 0.021827291629354928, + "win": 0.6585365853658537, + "best": 0.127016351044682, + "worst": -0.13338323548803055 + }, + "60": { + "n": 40, + "mean": 0.04572229219669499, + "median": 0.07306306891310688, + "win": 0.675, + "best": 0.2346876983518864, + "worst": -0.1876805086274399 + } + }, + "signal_dates": [ + "2021-08-19", + "2021-09-20", + "2021-09-28", + "2021-11-26", + "2021-12-14", + "2022-01-10", + "2022-01-14", + "2022-02-10", + "2022-04-06", + "2022-04-21", + "2022-08-22", + "2022-11-28", + "2022-12-06", + "2022-12-22", + "2023-01-10", + "2023-02-21", + "2023-03-09", + "2023-10-23", + "2023-10-27", + "2024-08-02", + "2024-09-04", + "2024-09-06", + "2024-10-07", + "2024-10-31", + "2024-12-18", + "2025-01-13", + "2025-01-27", + "2025-02-28", + "2025-03-28", + "2025-05-22", + "2025-06-13", + "2025-06-23", + "2025-10-10", + "2025-10-14", + "2025-11-07", + "2025-11-14", + "2026-02-05", + "2026-02-13", + "2026-02-23", + "2026-03-02", + "2026-06-09" + ] + } + } +} \ No newline at end of file diff --git a/vix_qqq_results_5y.json b/vix_qqq_results_5y.json new file mode 100644 index 0000000..ea0bf5b --- /dev/null +++ b/vix_qqq_results_5y.json @@ -0,0 +1,538 @@ +{ + "data_span": "2021-08-10 to 2026-08-07", + "trading_days": 1254, + "thresholds": [ + 17, + 18, + 19, + 20, + 21, + 22 + ], + "horizons": [ + 5, + 20, + 60 + ], + "buy_and_hold": { + "5": { + "n": 1249, + "mean": 0.003138296789026028, + "median": 0.0051984480660698384, + "win": 0.5748598879103283, + "best": 0.10077871682407125, + "worst": -0.11982232533480563 + }, + "20": { + "n": 1234, + "mean": 0.01202913585405011, + "median": 0.01545511618643891, + "win": 0.6191247974068071, + "best": 0.20525969712266257, + "worst": -0.15937638583593183 + }, + "60": { + "n": 1194, + "mean": 0.03836659718447432, + "median": 0.04653715628976818, + "win": 0.6758793969849246, + "best": 0.3268039045717981, + "worst": -0.24105061455776944 + } + }, + "strategy": { + "17": { + "total_signals": 52, + "horizons": { + "5": { + "n": 51, + "mean": -0.000397887254264299, + "median": 0.0029504630475947202, + "win": 0.6078431372549019, + "best": 0.03794034703293514, + "worst": -0.04930729886574403 + }, + "20": { + "n": 49, + "mean": 0.009383555926493871, + "median": 0.01501830979627572, + "win": 0.6530612244897959, + "best": 0.08957976364882358, + "worst": -0.11349610607709382 + }, + "60": { + "n": 46, + "mean": 0.028079584256733712, + "median": 0.047912148321742065, + "win": 0.6739130434782609, + "best": 0.20070137492494355, + "worst": -0.17956826849498064 + } + }, + "signal_dates": [ + "2021-08-16", + "2021-08-31", + "2021-09-03", + "2021-10-18", + "2021-10-27", + "2021-11-05", + "2023-05-02", + "2023-07-06", + "2023-08-03", + "2023-08-17", + "2023-09-21", + "2024-02-13", + "2024-04-11", + "2024-04-25", + "2024-07-19", + "2024-07-24", + "2024-08-01", + "2024-08-21", + "2024-08-28", + "2024-09-03", + "2024-09-30", + "2024-11-15", + "2024-12-18", + "2024-12-27", + "2025-01-07", + "2025-01-27", + "2025-01-31", + "2025-02-12", + "2025-02-21", + "2025-06-27", + "2025-07-07", + "2025-07-11", + "2025-07-22", + "2025-07-30", + "2025-08-20", + "2025-09-02", + "2025-09-23", + "2025-10-01", + "2025-10-03", + "2025-10-29", + "2025-12-08", + "2025-12-12", + "2026-01-14", + "2026-01-20", + "2026-01-26", + "2026-01-28", + "2026-06-05", + "2026-06-17", + "2026-07-08", + "2026-07-13", + "2026-07-16", + "2026-08-05" + ] + }, + "18": { + "total_signals": 57, + "horizons": { + "5": { + "n": 56, + "mean": 0.002526733304778989, + "median": 0.006194204073668996, + "win": 0.6071428571428571, + "best": 0.06005524439913912, + "worst": -0.06184163412063948 + }, + "20": { + "n": 54, + "mean": 0.011578655551448581, + "median": 0.014493890245094954, + "win": 0.6481481481481481, + "best": 0.11160072299361556, + "worst": -0.08747019674920486 + }, + "60": { + "n": 50, + "mean": 0.04132396163462907, + "median": 0.06108182125506367, + "win": 0.72, + "best": 0.20070137492494355, + "worst": -0.17956826849498064 + } + }, + "signal_dates": [ + "2021-08-17", + "2021-08-26", + "2021-09-07", + "2021-10-29", + "2021-11-09", + "2021-11-18", + "2021-12-31", + "2022-01-05", + "2023-04-24", + "2023-05-02", + "2023-05-10", + "2023-05-15", + "2023-05-22", + "2023-08-08", + "2023-08-17", + "2023-09-25", + "2023-10-02", + "2023-10-12", + "2024-04-12", + "2024-07-24", + "2024-07-30", + "2024-08-01", + "2024-08-22", + "2024-09-03", + "2024-09-17", + "2024-10-01", + "2024-11-20", + "2024-12-18", + "2024-12-27", + "2025-01-02", + "2025-01-07", + "2025-01-27", + "2025-02-03", + "2025-02-21", + "2025-03-26", + "2025-05-19", + "2025-06-11", + "2025-07-07", + "2025-07-16", + "2025-08-01", + "2025-09-02", + "2025-10-10", + "2025-10-31", + "2025-12-17", + "2026-01-14", + "2026-01-20", + "2026-01-29", + "2026-02-11", + "2026-05-04", + "2026-05-11", + "2026-06-05", + "2026-06-17", + "2026-06-23", + "2026-07-08", + "2026-07-17", + "2026-07-22", + "2026-08-05" + ] + }, + "19": { + "total_signals": 54, + "horizons": { + "5": { + "n": 54, + "mean": 0.005179920047556141, + "median": 0.008431420238394827, + "win": 0.6111111111111112, + "best": 0.06005524439913912, + "worst": -0.0687655588859718 + }, + "20": { + "n": 52, + "mean": 0.016763236651556733, + "median": 0.014847447458760099, + "win": 0.6923076923076923, + "best": 0.12384656729048382, + "worst": -0.14466646189504417 + }, + "60": { + "n": 49, + "mean": 0.0526922446635316, + "median": 0.07757908753862908, + "win": 0.7551020408163265, + "best": 0.21174882001450723, + "worst": -0.177732089231886 + } + }, + "signal_dates": [ + "2021-08-17", + "2021-08-26", + "2021-09-08", + "2021-11-10", + "2021-11-19", + "2021-12-27", + "2022-01-05", + "2022-01-13", + "2023-04-25", + "2023-05-02", + "2023-05-04", + "2023-05-23", + "2023-09-26", + "2023-10-03", + "2023-10-13", + "2023-10-18", + "2024-04-12", + "2024-04-19", + "2024-07-25", + "2024-08-01", + "2024-09-03", + "2024-09-18", + "2024-10-01", + "2024-12-18", + "2024-12-30", + "2025-01-02", + "2025-01-08", + "2025-01-27", + "2025-02-03", + "2025-02-21", + "2025-03-26", + "2025-05-15", + "2025-05-19", + "2025-05-21", + "2025-06-13", + "2025-07-16", + "2025-08-01", + "2025-09-02", + "2025-10-10", + "2025-10-22", + "2025-11-04", + "2025-11-13", + "2026-01-20", + "2026-01-29", + "2026-02-12", + "2026-04-16", + "2026-04-20", + "2026-05-04", + "2026-05-12", + "2026-05-15", + "2026-06-05", + "2026-06-23", + "2026-07-17", + "2026-07-22" + ] + }, + "20": { + "total_signals": 53, + "horizons": { + "5": { + "n": 53, + "mean": 0.007293232225419666, + "median": 0.00934738410944691, + "win": 0.660377358490566, + "best": 0.08397686211051614, + "worst": -0.09866931541941393 + }, + "20": { + "n": 51, + "mean": 0.016870468211586862, + "median": 0.016128753968992937, + "win": 0.6274509803921569, + "best": 0.1217066098444064, + "worst": -0.10645887101835971 + }, + "60": { + "n": 48, + "mean": 0.06360778893320072, + "median": 0.08571230647702632, + "win": 0.8333333333333334, + "best": 0.21070940407956984, + "worst": -0.2033288427237785 + } + }, + "signal_dates": [ + "2021-08-18", + "2021-09-10", + "2021-09-17", + "2021-09-28", + "2021-10-11", + "2021-11-23", + "2022-01-05", + "2022-01-13", + "2022-03-30", + "2023-01-17", + "2023-01-30", + "2023-02-08", + "2023-02-16", + "2023-03-08", + "2023-03-30", + "2023-04-04", + "2023-04-10", + "2023-05-04", + "2023-05-24", + "2023-10-03", + "2023-10-13", + "2023-10-18", + "2024-04-19", + "2024-08-02", + "2024-09-03", + "2024-10-01", + "2024-10-23", + "2024-10-29", + "2024-12-18", + "2025-01-10", + "2025-01-27", + "2025-02-03", + "2025-02-24", + "2025-03-28", + "2025-05-21", + "2025-05-29", + "2025-06-13", + "2025-08-01", + "2025-10-10", + "2025-10-22", + "2025-11-04", + "2025-11-13", + "2026-01-20", + "2026-02-03", + "2026-02-12", + "2026-02-26", + "2026-04-21", + "2026-04-23", + "2026-06-05", + "2026-06-23", + "2026-06-26", + "2026-07-23", + "2026-07-29" + ] + }, + "21": { + "total_signals": 50, + "horizons": { + "5": { + "n": 50, + "mean": 0.0025563136078792592, + "median": 0.0068010314914316305, + "win": 0.56, + "best": 0.06610940521499553, + "worst": -0.09866931541941393 + }, + "20": { + "n": 50, + "mean": 0.012299137922432953, + "median": 0.018978022799173933, + "win": 0.64, + "best": 0.1553312510788094, + "worst": -0.13595743196109733 + }, + "60": { + "n": 48, + "mean": 0.0482895516351726, + "median": 0.07565524390627876, + "win": 0.7291666666666666, + "best": 0.2126699564530663, + "worst": -0.2186928825419765 + } + }, + "signal_dates": [ + "2021-08-18", + "2021-09-10", + "2021-09-17", + "2021-09-28", + "2021-11-26", + "2022-01-06", + "2022-01-10", + "2022-01-14", + "2022-03-31", + "2022-04-05", + "2022-08-15", + "2022-08-19", + "2022-12-05", + "2023-01-19", + "2023-02-09", + "2023-02-17", + "2023-03-09", + "2023-05-04", + "2023-10-19", + "2023-10-25", + "2024-04-19", + "2024-08-02", + "2024-09-03", + "2024-09-11", + "2024-10-07", + "2024-10-16", + "2024-10-31", + "2024-12-18", + "2025-01-13", + "2025-01-27", + "2025-02-25", + "2025-02-27", + "2025-03-28", + "2025-05-21", + "2025-06-13", + "2025-06-17", + "2025-08-01", + "2025-10-10", + "2025-10-14", + "2025-10-22", + "2025-11-07", + "2025-11-13", + "2026-02-04", + "2026-02-12", + "2026-02-19", + "2026-02-27", + "2026-04-13", + "2026-04-23", + "2026-06-05", + "2026-06-09" + ] + }, + "22": { + "total_signals": 41, + "horizons": { + "5": { + "n": 41, + "mean": 0.004729890061364004, + "median": 0.00758437839065218, + "win": 0.5853658536585366, + "best": 0.06486923070532713, + "worst": -0.09866931541941393 + }, + "20": { + "n": 41, + "mean": 0.009766392712114847, + "median": 0.021827291629354928, + "win": 0.6585365853658537, + "best": 0.127016351044682, + "worst": -0.13338323548803055 + }, + "60": { + "n": 40, + "mean": 0.04572229219669499, + "median": 0.07306306891310688, + "win": 0.675, + "best": 0.2346876983518864, + "worst": -0.1876805086274399 + } + }, + "signal_dates": [ + "2021-08-19", + "2021-09-20", + "2021-09-28", + "2021-11-26", + "2021-12-14", + "2022-01-10", + "2022-01-14", + "2022-02-10", + "2022-04-06", + "2022-04-21", + "2022-08-22", + "2022-11-28", + "2022-12-06", + "2022-12-22", + "2023-01-10", + "2023-02-21", + "2023-03-09", + "2023-10-23", + "2023-10-27", + "2024-08-02", + "2024-09-04", + "2024-09-06", + "2024-10-07", + "2024-10-31", + "2024-12-18", + "2025-01-13", + "2025-01-27", + "2025-02-28", + "2025-03-28", + "2025-05-22", + "2025-06-13", + "2025-06-23", + "2025-10-10", + "2025-10-14", + "2025-11-07", + "2025-11-14", + "2026-02-05", + "2026-02-13", + "2026-02-23", + "2026-03-02", + "2026-06-09" + ] + } + } +} \ No newline at end of file diff --git a/vix_qqq_strategies.py b/vix_qqq_strategies.py new file mode 100644 index 0000000..9398d3b --- /dev/null +++ b/vix_qqq_strategies.py @@ -0,0 +1,211 @@ +#!/usr/bin/env python3 +""" +Compare several long/flat QQQ trading strategies against buy & hold. + +Execution model (no look-ahead): + * A strategy outputs a target position (1 = long QQQ, 0 = cash) that is + DECIDED using data up to and including day t's close. + * That position earns the QQQ close-to-close return from day t to t+1. + * A round-trip costs COST per side (applied when the position changes). + +Metrics per strategy: + total return, CAGR, annual vol, Sharpe (rf=0), max drawdown, + exposure (% of days invested), number of trades, average trades/year. + +Strategies: + BH Buy & Hold + SMA 200-day trend filter: long when Close > SMA200 else cash + RSI2 Connors-style mean reversion: (Close>SMA200) & RSI(2)<10 -> long, + exit when Close>SMA5 or RSI(2)>70 (frequent, short holds) + DIP Above SMA200, buy after 3 consecutive down days, exit on first up day + VIXR VIX spike dip-buy: above SMA200, enter when VIX High >= 1.10 * prior + VIX close, hold 10 trading days (overlaps extend the hold) +""" + +import sys +import numpy as np +import pandas as pd +import requests + +CA_BUNDLE = "/root/.ccr/ca-bundle.crt" +HEADERS = {"User-Agent": "Mozilla/5.0"} +COST = 0.0002 # 0.02% per side +TRADING_DAYS = 252 + + +def fetch_yahoo(symbol): + url = f"https://query1.finance.yahoo.com/v8/finance/chart/{symbol}" + params = {"period1": 0, "period2": 9999999999, "interval": "1d"} + r = requests.get(url, params=params, headers=HEADERS, timeout=60, verify=CA_BUNDLE) + r.raise_for_status() + res = r.json()["chart"]["result"][0] + q = res["indicators"]["quote"][0] + df = pd.DataFrame( + {"open": q["open"], "high": q["high"], "low": q["low"], "close": q["close"]}, + index=pd.to_datetime(res["timestamp"], unit="s").normalize(), + ).dropna(subset=["high", "close"]) + df.index.name = "date" + return df + + +def rsi(series, n): + delta = series.diff() + up = delta.clip(lower=0).rolling(n).mean() + down = (-delta.clip(upper=0)).rolling(n).mean() + rs = up / down.replace(0, np.nan) + return 100 - 100 / (1 + rs) + + +def build(df): + d = pd.DataFrame(index=df.index) + d["close"] = df["qqq_close"] + d["ret"] = d["close"].pct_change() + d["sma200"] = d["close"].rolling(200).mean() + d["sma5"] = d["close"].rolling(5).mean() + d["rsi2"] = rsi(d["close"], 2) + d["up"] = d["close"].diff() > 0 + d["vix_high"] = df["vix_high"] + d["vix_close"] = df["vix_close"] + return d + + +# --- position generators: return a 0/1 Series aligned to d.index --- + +def pos_bh(d): + return pd.Series(1.0, index=d.index) + + +def pos_sma(d): + return (d["close"] > d["sma200"]).astype(float) + + +def pos_rsi2(d): + above = d["close"] > d["sma200"] + pos = np.zeros(len(d)) + invested = False + r2 = d["rsi2"].values + c = d["close"].values + s5 = d["sma5"].values + ab = above.values + for i in range(len(d)): + if invested: + if c[i] > s5[i] or r2[i] > 70: + invested = False + else: + if ab[i] and r2[i] < 10: + invested = True + pos[i] = 1.0 if invested else 0.0 + return pd.Series(pos, index=d.index) + + +def pos_dip(d): + above = d["close"] > d["sma200"] + down = ~d["up"] + three_down = down & down.shift(1) & down.shift(2) + pos = np.zeros(len(d)) + invested = False + td = three_down.fillna(False).values + upv = d["up"].values + ab = above.values + for i in range(len(d)): + if invested: + if upv[i]: + invested = False + else: + if ab[i] and td[i]: + invested = True + pos[i] = 1.0 if invested else 0.0 + return pd.Series(pos, index=d.index) + + +def pos_vixr(d, hold=10): + above = d["close"] > d["sma200"] + spike = d["vix_high"] >= 1.10 * d["vix_close"].shift(1) + entry = (above & spike).fillna(False).values + pos = np.zeros(len(d)) + remaining = 0 + for i in range(len(d)): + if entry[i]: + remaining = hold + if remaining > 0: + pos[i] = 1.0 + remaining -= 1 + return pd.Series(pos, index=d.index) + + +STRATS = { + "BH": pos_bh, + "SMA": pos_sma, + "RSI2": pos_rsi2, + "DIP": pos_dip, + "VIXR": pos_vixr, +} + + +def evaluate(d, pos): + # position decided at t's close earns t->t+1 return: shift position by 1. + held = pos.shift(1).fillna(0.0) + trades_series = pos.diff().abs().fillna(0.0) # 1 each time exposure flips + cost = trades_series * COST + strat_ret = held * d["ret"].fillna(0.0) - cost + equity = (1 + strat_ret).cumprod() + + n = len(d) + years = n / TRADING_DAYS + total = equity.iloc[-1] - 1 + cagr = equity.iloc[-1] ** (1 / years) - 1 if years > 0 else np.nan + vol = strat_ret.std() * np.sqrt(TRADING_DAYS) + sharpe = (strat_ret.mean() * TRADING_DAYS) / vol if vol > 0 else np.nan + dd = (equity / equity.cummax() - 1).min() + exposure = held.mean() + # count entries (0->1) as trades + entries = int(((pos > 0) & (pos.shift(1).fillna(0) == 0)).sum()) + return { + "total": total, "cagr": cagr, "vol": vol, "sharpe": sharpe, + "maxdd": dd, "exposure": exposure, "trades": entries, + "trades_yr": entries / years if years > 0 else np.nan, + "equity": equity, + } + + +def run(d, label): + print("=" * 92) + print(f"{label} ({d.index[0].date()} -> {d.index[-1].date()}, " + f"{len(d)} trading days)") + print("=" * 92) + hdr = (f"{'Strat':>5} {'TotRet':>9} {'CAGR':>8} {'Vol':>7} {'Sharpe':>7} " + f"{'MaxDD':>8} {'Expo':>6} {'Trades':>7} {'Tr/yr':>6}") + print(hdr) + for name, fn in STRATS.items(): + m = evaluate(d, fn(d)) + print(f"{name:>5} {m['total']*100:>8.1f}% {m['cagr']*100:>7.1f}% " + f"{m['vol']*100:>6.1f}% {m['sharpe']:>7.2f} {m['maxdd']*100:>7.1f}% " + f"{m['exposure']*100:>5.0f}% {m['trades']:>7} {m['trades_yr']:>6.1f}") + print() + + +def main(): + vix = fetch_yahoo("%5EVIX") + qqq = fetch_yahoo("QQQ") + base = pd.DataFrame({ + "vix_high": vix["high"], + "vix_close": vix["close"], + "qqq_close": qqq["close"], + }).dropna().sort_index() + d_full = build(base) + + # 5-year window; keep SMA200 warm-up by computing indicators on full history + # then slicing. + start = pd.Timestamp("2021-08-10") + d_5y = d_full[d_full.index >= start].copy() + + run(d_full, "FULL HISTORY") + run(d_5y, "LAST 5 YEARS") + + print("Legend: BH=buy&hold SMA=200d trend filter RSI2=Connors mean-revert") + print(" DIP=3-down-days dip buy VIXR=VIX-spike 10d dip buy") + print("Execution: next-day fills, 0.02%/side cost, long/flat only.") + + +if __name__ == "__main__": + main()