Overall Statistics
Total Trades
35623
Average Win
0.03%
Average Loss
-0.02%
Compounding Annual Return
40.917%
Drawdown
16.900%
Expectancy
0.163
Net Profit
74.091%
Sharpe Ratio
1.745
Probabilistic Sharpe Ratio
77.217%
Loss Rate
59%
Win Rate
41%
Profit-Loss Ratio
1.81
Alpha
0.374
Beta
-0.083
Annual Standard Deviation
0.203
Annual Variance
0.041
Information Ratio
0.365
Tracking Error
0.338
Treynor Ratio
-4.253
Total Fees
$36010.68
Estimated Strategy Capacity
$98000000.00
Lowest Capacity Asset
NWSVV VHJF6S7EZRL1
max_drawdown = 0.05

market = 'SPY'
silver = 'SLV'
gold = 'GLD'
utility = 'XLU'
industrial = 'XLI'
safe = 'FXF'
risk = 'FXA'
debt_short = 'SHY'
debt_inflation = 'TIP'
metal = 'DBB'
inp = 'IGE'
cash = 'UUP'


equities = ['A','AAP','AAPL','ABC','ABMD','ABT','ADBE','ADI','ADM','ADP','ADSK','AGN','AGR','AKAM','ALB','ALGN','ALK','ALLE','ALV','ALXN','AMAT','AMD','AME','AMGN','AMT','ANET','ANSS','AOS','APD','APTV','ARW','ASH','ATO','ATVI','AVB','AVY','AYI','AZO','BAX','BBY','BG','BIIB','BIO','BKNG','BKR','BMRN','BSX','BURL','BWA','CAH','CCEP','CDNS','CDW','CERN','CF','CGNX','CHD','CHRW','CL','CLX','CMI','COG','COO','COP','CPRI','CPRT','CRM','CSCO','CSX','CTAS','CTSH','CTVA','CTXS','CVS','CVX','CXO','DAL','DD','DGX','DHI','DHR','DLTR','DOV','DOW','DOX','DRE','DVA','DVN','EBAY','ECL','EIX','EL','ELAN','EMR','EOG','EQIX','ETN','EW','EXC','EXPD','EXPE','FANG','FAST','FB','FCX','FDX','FFIV','FISV','FL','FLEX','FLS','FLT','FMC','FTI','FTNT','FTV','GDDY','GILD','GLW','GNTX','GOOG','GOOGL','GPC','GPS','GRMN','GRUB','GWW','HAL','HAS','HD','HEI','HEIA','HES','HFC','HOLX','HP','HPE','HPQ','HSIC','HSY','IBM','IDXX','IEX','IFF','ILMN','INCY','INFO','INTC','INTU','IP','IPG','IPGP','IR','ISRG','IT','ITW','JAZZ','JBHT','JBL','JCI','JNJ','JNPR','JWN','KDP','KEYS','KHC','KLAC','KMB','KNX','KO','KSS','KSU','LDOS','LEA','LEN','LIN','LKQ','LLY','LOW','LRCX','LULU','LUV','LW','LYB','M','MAS','MCD','MCK','MDLZ','MDT','MDU','MHK','MKC','MLM','MMM','MNST','MOS','MPC','MRK','MRO','MRVL','MSFT','MSI','MTD','MU','MXIM','NBL','NEM','NKE','NLOK','NOV','NOW','NSC','NTAP','NUE','NVDA','NVR','NWS','NWSA','NXPI','ODFL','OGE','OMC','ORCL','ORLY','OXY','PAYC','PAYX','PCG','PEG','PEP','PFE','PG','PHM','PKG','PKI','PLD','PNR','PNW','PPG','PRGO','PSA','PSX','PTC','PVH','PXD','QCOM','QRVO','REGN','RHI','RL','RMD','ROK','ROL','ROP','ROST','SBUX','SCCO','SHW','SLB','SNA','SNPS','ST','STE','STLD','STX','SWK','SWKS','SYK','TEL','TFX','TGT','TIF','TJX','TMO','TOL','TPR','TRMB','TSCO','TSLA','TT','TWTR','TXN','TYL','UA','UAA','UAL','ULTA','UNP','UPS','VAR','VFC','VLO','VMC','VMW','VRSN','VRTX','WAB','WAT','WBA','WBC','WDAY','WDC','WHR','WLK','WY','XEC','XOM','XRAY','XRX','XYL','YNDX','ZBRA']

#equities = ['ATVI', 'ADBE', 'AMD', 'ALGN', 'ALXN', 'AMZN', 'AMGN', 'AAL', 'ADI', 'AAPL', 'AMAT', 'ASML', 'ADSK', 'ADP', 'AVGO', 'BIDU', 'BIIB', 'BMRN', 'CDNS', 'CERN', 'CHKP', 'CHTR', 'TCOM', 'CTAS', 'CSCO', 'CTXS', 'CMCSA', 'COST', 'CSX', 'CTSH', 'DLTR', 'EA', 'EBAY', 'EXC', 'EXPE', 'FAST', 'FB', 'FISV', 'GILD', 'GOOG', 'GOOGL', 'HAS', 'HSIC', 'ILMN', 'INCY', 'INTC', 'INTU', 'ISRG', 'IDXX', 'JBHT', 'JD', 'KLAC', 'KHC', 'LRCX', 'LBTYA', 'LBTYK', 'LULU', 'MELI', 'MAR', 'MCHP', 'MDLZ', 'MNST', 'MSFT', 'MU', 'MXIM', 'MYL', 'NTAP', 'NFLX', 'NTES', 'NVDA', 'NXPI', 'ORLY', 'PAYX', 'PCAR', 'BKNG', 'PYPL', 'PEP', 'QCOM', 'REGN', 'ROST', 'SIRI', 'SWKS', 'SBUX', 'NLOK', 'SNPS', 'TTWO', 'TSLA', 'TXN', 'TMUS', 'ULTA', 'UAL', 'VRSN', 'VRSK', 'VRTX', 'WBA', 'WDC', 'WDAY', 'WYNN', 'XEL', 'XLNX']

#'AAN', 'AAOI', 'AAON', 'AAT', 'AAWW', 'AAXN', 'ABCB', 'ABEO', 'ABG', 'ABM', 'ABTX', 'AC', 'ACA', 'ACAD', 'ACBI', 'ACCO', 'ACER', 'ACHN', 'ACIA', 'ACIW', 'ACLS', 'ACNB', 'ACOR', 'ACRE', 'ACRS', 'ACRX', 'ACTG', 'ADC', 'ADES', 'ADMA', 'ADMS', 'ADNT', 'ADRO', 'ADSW', 'ADTN', 'ADUS', 'ADVM', 'AEGN', 'AEIS', 'AEL', 'AEO', 'AERI', 'AFI', 'AFIN', 'AFMD', 'AGE', 'AGEN', 'AGLE', 'AGM', 'AGS', 'AGX', 'AGYS', 'AHH', 'AHT', 'AI', 'AIMC', 'AIMT', 'AIN', 'AIR', 'AIRG', 'AIT', 'AJRD', 'AJX', 'AKBA', 'AKCA', 'AKR', 'AKRO', 'AKRX', 'AKS', 'AKTS', 'ALBO', 'ALCO', 'ALDR', 'ALDX', 'ALE', 'ALEC', 'ALEX', 'ALG', 'ALGT', 'ALLK', 'ALLO', 'ALOT', 'ALRM', 'ALTM', 'ALTR', 'ALX', 'AMAG', 'AMAL', 'AMBA', 'AMBC', 'AMC', 'AMED', 'AMEH', 'AMK', 'AMKR', 'AMN', 'AMNB', 'AMOT', 'AMPH', 'AMRC', 'AMRS', 'AMRX', 'AMSC', 'AMSF', 'AMSWA', 'AMTB', 'AMWD', 'ANAB', 'ANDE', 'ANF', 'ANGO', 'ANH', 'ANIK', 'ANIP', 'AOBC', 'AOSL', 'APAM', 'APEI', 'APLS', 'APOG', 'APPF', 'APPN', 'APPS', 'APTS', 'APYX', 'AQUA', 'ARA', 'ARAY', 'ARCB', 'ARCH', 'ARDX', 'ARES', 'ARGO', 'ARI', 'ARL', 'ARLO', 'ARNA', 'AROC', 'AROW', 'ARQL', 'ARR', 'ARTNA', 'ARVN', 'ARWR', 'ASC', 'ASGN', 'ASIX', 'ASMB', 'ASNA', 'ASPS', 'ASRT', 'ASTE', 'AT', 'ATEC', 'ATEN', 'ATEX', 'ATGE', 'ATHX', 'ATI', 'ATKR', 'ATLO', 'ATNI', 'ATNX', 'ATRA', 'ATRC', 'ATRI', 'ATRO', 'ATRS', 'ATSG', 'AUB', 'AVA', 'AVAV', 'AVCO', 'AVD', 'AVDR', 'AVID', 'AVNS', 'AVRO', 'AVX', 'AVXL', 'AVYA', 'AWR', 'AX', 'AXAS', 'AXDX', 'AXE', 'AXGN', 'AXL', 'AXLA', 'AXNX', 'AXSM', 'AXTI', 'AYR', 'AZZ', 'B', 'BANC', 'BAND', 'BANF', 'BANR', 'BATRA', 'BATRK', 'BBBY', 'BBCP', 'BBIO', 'BBSI', 'BBX', 'BCBP', 'BCC', 'BCEI', 'BCEL', 'BCML', 'BCO', 'BCOR', 'BCOV', 'BCPC', 'BCRX', 'BDC', 'BDGE', 'BDSI', 'BE', 'BEAT', 'BECN', 'BELFB', 'BFC', 'BFIN', 'BFS', 'BFST', 'BGG', 'BGS', 'BGSF', 'BH', 'BHB', 'BHE', 'BHLB', 'BHR', 'BHVN', 'BIG', 'BIOS', 'BJ', 'BJRI', 'BKD', 'BKE', 'BKH', 'BL', 'BLBD', 'BLD', 'BLDR', 'BLFS', 'BLKB', 'BLMN', 'BLX', 'BMCH', 'BMI', 'BMRC', 'BMTC', 'BNED', 'BNFT', 'BOCH', 'BOLD', 'BOMN', 'BOOM', 'BOOT', 'BOX', 'BPFH', 'BPMC', 'BPRN', 'BRC', 'BREW', 'BRG', 'BRID', 'BRKL', 'BRKS', 'BRT', 'BRY', 'BSET', 'BSGM', 'BSIG', 'BSRR', 'BSTC', 'BSVN', 'BTAI', 'BTU', 'BUSE', 'BV', 'BWB', 'BWFG', 'BXC', 'BXG', 'BXMT', 'BXS', 'BY', 'BYD', 'BYSI', 'BZH', 'CAC', 'CADE', 'CAI', 'CAKE', 'CAL', 'CALA', 'CALM', 'CALX', 'CAMP', 'CAR', 'CARA', 'CARB', 'CARE', 'CARG', 'CARO', 'CARS', 'CASA', 'CASH', 'CASI', 'CASS', 'CATC', 'CATM', 'CATO', 'CATS', 'CATY', 'CBAN', 'CBAY', 'CBB', 'CBL', 'CBLK', 'CBM', 'CBMG', 'CBNK', 'CBPX', 'CBRL', 'CBTX', 'CBU', 'CBZ', 'CCB', 'CCBG', 'CCF', 'CCMP', 'CCNE', 'CCO', 'CCOI', 'CCRN', 'CCS', 'CCXI', 'CDE', 'CDLX', 'CDMO', 'CDNA', 'CDR', 'CDXC', 'CDXS', 'CDZI', 'CECE', 'CECO', 'CEIX', 'CELC', 'CELH', 'CENT', 'CENTA', 'CENX', 'CERC', 'CERS', 'CETV', 'CEVA', 'CFB', 'CFFI', 'CFFN', 'CFMS', 'CHAP', 'CHCO', 'CHCT', 'CHDN', 'CHEF', 'CHGG', 'CHMA', 'CHMG', 'CHMI', 'CHRA', 'CHRS', 'CHS', 'CHUY', 'CIA', 'CIO', 'CIR', 'CISN', 'CIVB', 'CIX', 'CJ', 'CKH', 'CKPT', 'CLAR', 'CLBK', 'CLCT', 'CLDR', 'CLDT', 'CLF', 'CLFD', 'CLI', 'CLNC', 'CLNE', 'CLPR', 'CLVS', 'CLW', 'CLXT', 'CMBM', 'CMC', 'CMCO', 'CMCT', 'CMLS', 'CMO', 'CMP', 'CMPR', 'CMRE', 'CMRX', 'CMTL', 'CNBKA', 'CNCE', 'CNDT', 'CNMD', 'CNNE', 'CNO', 'CNOB', 'CNR', 'CNS', 'CNSL', 'CNST', 'CNTY', 'CNX', 'CNXN', 'CODA', 'COHU', 'COKE', 'COLB', 'COLL', 'CONN', 'COOP', 'CORE', 'CORR', 'CORT', 'COWN', 'CPE', 'CPF', 'CPK', 'CPLG', 'CPRX', 'CPS', 'CPSI', 'CRAI', 'CRBP', 'CRC', 'CRCM', 'CRD.A', 'CRK', 'CRMD', 'CRMT', 'CRNX', 'CROX', 'CRS', 'CRTX', 'CRUS', 'CRVL', 'CRY', 'CRZO', 'CSFL', 'CSGS', 'CSII', 'CSLT', 'CSOD', 'CSTE', 'CSTL', 'CSTR', 'CSV', 'CSWI', 'CTB', 'CTBI', 'CTMX', 'CTO', 'CTRA', 'CTRC', 'CTRE', 'CTRN', 'CTS', 'CTSO', 'CTT', 'CTWS', 'CUB', 'CUBI', 'CUE', 'CULP', 'CURO', 'CUTR', 'CVA', 'CVBF', 'CVCO', 'CVCY', 'CVGI', 'CVGW', 'CVI', 'CVIA', 'CVLT', 'CVLY', 'CVM', 'CVRS', 'CVTI', 'CWCO', 'CWEN', 'CWEN.A', 'CWH', 'CWK', 'CWST', 'CWT', 'CXW', 'CYCN', 'CYH', 'CYRX', 'CYTK', 'CZNC', 'DAKT', 'DAN', 'DAR', 'DBD', 'DBI', 'DCO', 'DCOM', 'DCPH', 'DDD', 'DDS', 'DEA', 'DECK', 'DENN', 'DERM', 'DF', 'DFIN', 'DGICA', 'DGII', 'DHIL', 'DHT', 'DHX', 'DIN', 'DIOD', 'DJCO', 'DK', 'DLA', 'DLTH', 'DLX', 'DMRC', 'DNBF', 'DNLI', 'DNOW', 'DNR', 'DO', 'DOC', 'DOMO', 'DOOR', 'DORM', 'DOVA', 'DPLO', 'DRH', 'DRNA', 'DRQ', 'DS', 'DSKE', 'DSPG', 'DSSI', 'DTIL', 'DVAX', 'DX', 'DXPE', 'DY', 'DZSI', 'EAT', 'EB', 'EBF', 'EBIX', 'EBS', 'EBSB', 'EBTC', 'ECHO', 'ECOL', 'ECOM', 'ECOR', 'ECPG', 'EDIT', 'EE', 'EEX', 'EFC', 'EFSC', 'EGAN', 'EGBN', 'EGHT', 'EGLE', 'EGOV', 'EGP', 'EGRX', 'EHTH', 'EIDX', 'EIG', 'EIGI', 'EIGR', 'ELF', 'ELOX', 'ELVT', 'ELY', 'EME', 'EML', 'ENDP', 'ENFC', 'ENOB', 'ENPH', 'ENS', 'ENSG', 'ENTA', 'ENV', 'ENVA', 'ENZ', 'EOLS', 'EPAY', 'EPC', 'EPM', 'EPRT', 'EPZM', 'EQBK', 'ERA', 'ERI', 'ERII', 'EROS', 'ESCA', 'ESE', 'ESGR', 'ESNT', 'ESPR', 'ESQ', 'ESSA', 'ESTE', 'ESXB', 'ETH', 'ETM', 'EVBG', 'EVBN', 'EVC', 'EVER', 'EVFM', 'EVH', 'EVI', 'EVLO', 'EVOP', 'EVRI', 'EVTC', 'EXLS', 'EXPI', 'EXPO', 'EXPR', 'EXTN', 'EXTR', 'EYE', 'EYPT', 'EZPW', 'FARM', 'FARO', 'FATE', 'FBC', 'FBIZ', 'FBK', 'FBM', 'FBMS', 'FBNC', 'FBP', 'FC', 'FCAP', 'FCBC', 'FCBP', 'FCCY', 'FCF', 'FCFS', 'FCN', 'FCPT', 'FDBC', 'FDEF', 'FDP', 'FELE', 'FET', 'FF', 'FFBC', 'FFG', 'FFIC', 'FFIN', 'FFNW', 'FFWM', 'FG', 'FGBI', 'FGEN', 'FI', 'FIBK', 'FII', 'FISI', 'FIT', 'FIVN', 'FIX', 'FIXX', 'FIZZ', 'FLDM', 'FLIC', 'FLMN', 'FLNT', 'FLOW', 'FLWS', 'FLXN', 'FLXS', 'FMAO', 'FMBH', 'FMBI', 'FMNB', 'FN', 'FNCB', 'FNHC', 'FNKO', 'FNLC', 'FNWB', 'FOCS', 'FOE', 'FOLD', 'FOR', 'FORM', 'FORR', 'FOSL', 'FOXF', 'FPI', 'FPRX', 'FR', 'FRAC', 'FRAF', 'FRBA', 'FRBK', 'FRGI', 'FRME', 'FRPH', 'FRPT', 'FRTA', 'FSB', 'FSBW', 'FSCT', 'FSP', 'FSS', 'FSTR', 'FTK', 'FTR', 'FTSI', 'FTSV', 'FUL', 'FULC', 'FULT', 'FVCB', 'FWRD', 'GABC', 'GAIA', 'GALT', 'GATX', 'GBCI', 'GBL', 'GBLI', 'GBT', 'GBX', 'GCAP', 'GCBC', 'GCI', 'GCO', 'GCP', 'GDEN', 'GDOT', 'GDP', 'GEF', 'GEF.B', 'GEN', 'GENC', 'GEO', 'GEOS', 'GERN', 'GES', 'GFF', 'GFN', 'GHDX', 'GHL', 'GHM', 'GIII', 'GKOS', 'GLDD', 'GLNG', 'GLOG', 'GLRE', 'GLT', 'GLUU', 'GLYC', 'GME', 'GMED', 'GMRE', 'GMS', 'GNC', 'GNE', 'GNK', 'GNL', 'GNLN', 'GNMK', 'GNRC', 'GNTY', 'GNW', 'GOGO', 'GOLF', 'GOOD', 'GORO', 'GOSS', 'GPI', 'GPMT', 'GPOR', 'GPRE', 'GPRO', 'GPX', 'GRBK', 'GRC', 'GRIF', 'GRPN', 'GRTS', 'GSBC', 'GSHD', 'GSIT', 'GTHX', 'GTLS', 'GTN', 'GTS', 'GTT', 'GTY', 'GTYH', 'GVA', 'GWB', 'GWGH', 'GWRS', 'HA', 'HABT', 'HAE', 'HAFC', 'HALL', 'HALO', 'HARP', 'HASI', 'HAYN', 'HBB', 'HBCP', 'HBMD', 'HBNC', 'HCAT', 'HCC', 'HCCI', 'HCI', 'HCKT', 'HCSG', 'HEES', 'HELE', 'HFFG', 'HFWA', 'HI', 'HIBB', 'HIFS', 'HIIQ', 'HL', 'HLI', 'HLIO', 'HLIT', 'HLNE', 'HLX', 'HMHC', 'HMN', 'HMST', 'HMSY', 'HMTV', 'HNGR', 'HNI', 'HNRG', 'HOFT', 'HOMB', 'HOME', 'HONE', 'HOOK', 'HOPE', 'HPR', 'HQY', 'HR', 'HRI', 'HRTG', 'HRTX', 'HSC', 'HSII', 'HSKA', 'HSTM', 'HT', 'HTBI', 'HTBK', 'HTH', 'HTLD', 'HTLF', 'HTZ', 'HUBG', 'HUD', 'HURC', 'HURN', 'HVT', 'HWBK', 'HWC', 'HWKN', 'HY', 'HZO', 'I', 'IBCP', 'IBKC', 'IBOC', 'IBP', 'IBTX', 'ICD', 'ICFI', 'ICHR', 'ICPT', 'IDCC', 'IDEX', 'IDT', 'IESC', 'IHC', 'III', 'IIIN', 'IIIV', 'IIN', 'IIPR', 'IIVI', 'ILPT', 'IMAX', 'IMGN', 'IMKTA', 'IMMR', 'IMMU', 'IMXI', 'INBK', 'INDB', 'INFN', 'INGN', 'INN', 'INO', 'INOV', 'INS', 'INSE', 'INSG', 'INSM', 'INSP', 'INST', 'INSW', 'INT', 'INTL', 'INVA', 'INWK', 'IOSP', 'IOTS', 'IOVA', 'IPAR', 'IPHI', 'IPHS', 'IPI', 'IRBT', 'IRDM', 'IRET', 'IRMD', 'IRT', 'IRTC', 'IRWD', 'ISBC', 'ISCA', 'ISRL', 'ISTR', 'ITCI', 'ITGR', 'ITI', 'ITIC', 'ITRI', 'IVC', 'IVR', 'JACK', 'JAG', 'JAX', 'JBSS', 'JBT', 'JCAP', 'JCOM', 'JCP', 'JELD', 'JILL', 'JJSF', 'JNCE', 'JOE', 'JOUT', 'JRVR', 'JYNT', 'KAI', 'KALA', 'KALU', 'KALV', 'KAMN', 'KBAL', 'KBH', 'KBR', 'KDMN', 'KE', 'KELYA', 'KEM', 'KFRC', 'KFY', 'KIDS', 'KIN', 'KLDO', 'KLXE', 'KMT', 'KN', 'KNL', 'KNSA', 'KNSL', 'KOD', 'KOP', 'KPTI', 'KRA', 'KREF', 'KRG', 'KRNY', 'KRO', 'KRTX', 'KRUS', 'KRYS', 'KTB', 'KTOS', 'KURA', 'KVHI', 'KW', 'KWR', 'KZR', 'LAD', 'LADR', 'LANC', 'LAND', 'LASR', 'LAUR', 'LAWS', 'LBAI', 'LBC', 'LBRT', 'LC', 'LCI', 'LCII', 'LCNB', 'LCTX', 'LCUT', 'LDL', 'LE', 'LEAF', 'LEE', 'LEGH', 'LEVL', 'LFVN', 'LGIH', 'LGND', 'LHCG', 'LILA', 'LILAK', 'LIND', 'LITE', 'LIVN', 'LIVX', 'LJPC', 'LKFN', 'LKSD', 'LL', 'LLNW', 'LMAT', 'LMNR', 'LMNX', 'LNDC', 'LNN', 'LNTH', 'LOB', 'LOCO', 'LOGC', 'LORL', 'LOVE', 'LPG', 'LPI', 'LPSN', 'LPX', 'LQDA', 'LQDT', 'LRN', 'LSCC', 'LTC', 'LTHM', 'LTRPA', 'LTS', 'LTXB', 'LVGO', 'LXFR', 'LXP', 'LXRX', 'LXU', 'LZB', 'MANT', 'MATW', 'MATX', 'MAXR', 'MBI', 'MBII', 'MBIN', 'MBIO', 'MBUU', 'MBWM', 'MC', 'MCB', 'MCBC', 'MCFT', 'MCHX', 'MCRB', 'MCRI', 'MCRN', 'MCS', 'MDC', 'MDCA', 'MDCO', 'MDGL', 'MDP', 'MDR', 'MDRX', 'MEC', 'MED', 'MEDP', 'MEET', 'MEI', 'MEIP', 'MESA', 'METC', 'MFIN', 'MFNC', 'MFSF', 'MG', 'MGEE', 'MGLN', 'MGNX', 'MGPI', 'MGRC', 'MGTA', 'MGTX', 'MGY', 'MHO', 'MIK', 'MINI', 'MIRM', 'MITK', 'MITT', 'MJCO', 'MLAB', 'MLHR', 'MLI', 'MLND', 'MLP', 'MLR', 'MLVF', 'MMAC', 'MMI', 'MMS', 'MMSI', 'MNK', 'MNKD', 'MNLO', 'MNOV', 'MNR', 'MNRL', 'MNRO', 'MNSB', 'MNTA', 'MOBL', 'MOD', 'MODN', 'MOFG', 'MOG.A', 'MORF', 'MOV', 'MPAA', 'MPB', 'MPX', 'MR', 'MRC', 'MRCY', 'MRKR', 'MRLN', 'MRNS', 'MRSN', 'MRTN', 'MRTX', 'MSA', 'MSBI', 'MSEX', 'MSGN', 'MSON', 'MSTR', 'MTDR', 'MTEM', 'MTH', 'MTOR', 'MTRN', 'MTRX', 'MTSC', 'MTSI', 'MTW', 'MTX', 'MTZ', 'MUSA', 'MVBF', 'MWA', 'MXL', 'MYE', 'MYGN', 'MYOK', 'MYRG', 'NANO', 'NAT', 'NATH', 'NATR', 'NAV', 'NBEV', 'NBHC', 'NBN', 'NBR', 'NBTB', 'NC', 'NCBS', 'NCI', 'NCMI', 'NCSM', 'NDLS', 'NE', 'NEO', 'NEOG', 'NERV', 'NESR', 'NEWM', 'NEXT', 'NFBK', 'NG', 'NGHC', 'NGM', 'NGS', 'NGVC', 'NGVT', 'NHC', 'NHI', 'NINE', 'NJR', 'NKSH', 'NL', 'NMIH', 'NMRK', 'NNBR', 'NNI', 'NODK', 'NOG', 'NOVA', 'NOVT', 'NP', 'NPK', 'NPO', 'NPTN', 'NR', 'NRC', 'NRCG', 'NRIM', 'NSA', 'NSIT', 'NSP', 'NSSC', 'NSTG', 'NTB', 'NTCT', 'NTGN', 'NTGR', 'NTLA', 'NTRA', 'NTUS', 'NUVA', 'NVAX', 'NVCR', 'NVEC', 'NVEE', 'NVRO', 'NVTA', 'NWBI', 'NWE', 'NWFL', 'NWLI', 'NWN', 'NWPX', 'NX', 'NXGN', 'NXRT', 'NXTC', 'NYMT', 'NYNY', 'OAS', 'OBNK', 'OCFC', 'OCN', 'OCUL', 'OCX', 'ODC', 'ODP', 'ODT', 'OEC', 'OFG', 'OFIX', 'OFLX', 'OGS', 'OII', 'OIS', 'OLBK', 'OLP', 'OMCL', 'OMER', 'OMI', 'OMN', 'ONB', 'ONCE', 'ONDK', 'OOMA', 'OPB', 'OPBK', 'OPI', 'OPK', 'OPRX', 'OPTN', 'OPY', 'ORA', 'ORBC', 'ORC', 'ORGO', 'ORIT', 'ORRF', 'OSBC', 'OSG', 'OSIS', 'OSMT', 'OSPN', 'OSTK', 'OSUR', 'OSW', 'OTTR', 'OVBC', 'OVLY', 'OXM', 'PACB', 'PACD', 'PAHC', 'PAR', 'PARR', 'PATK', 'PAYS', 'PBFS', 'PBH', 'PBI', 'PBIP', 'PBPB', 'PBYI', 'PCB', 'PCH', 'PCRX', 'PCSB', 'PCYO', 'PDCE', 'PDCO', 'PDFS', 'PDLB', 'PDLI', 'PDM', 'PEB', 'PEBK', 'PEBO', 'PEGI', 'PEI', 'PENN', 'PETQ', 'PETS', 'PFBC', 'PFBI', 'PFGC', 'PFIS', 'PFNX', 'PFS', 'PFSI', 'PGC', 'PGNX', 'PGTI', 'PHAS', 'PHR', 'PHUN', 'PHX', 'PI', 'PICO', 'PIRS', 'PJC', 'PJT', 'PKBK', 'PKD', 'PKE', 'PKOH', 'PLAB', 'PLAY', 'PLCE', 'PLMR', 'PLOW', 'PLPC', 'PLSE', 'PLT', 'PLUG', 'PLUS', 'PLXS', 'PMBC', 'PMT', 'PNM', 'PNRG', 'PNTG', 'POL', 'POR', 'POWI', 'POWL', 'PPBI', 'PQG', 'PRA', 'PRAA', 'PRFT', 'PRGS', 'PRGX', 'PRIM', 'PRK', 'PRLB', 'PRMW', 'PRNB', 'PRO', 'PROS', 'PROV', 'PRPL', 'PRSC', 'PRSP', 'PRTA', 'PRTH', 'PRTK', 'PRTY', 'PRVL', 'PSB', 'PSDO', 'PSMT', 'PSN', 'PSNL', 'PTCT', 'PTE', 'PTGX', 'PTLA', 'PTN', 'PTSI', 'PTVCB', 'PUB', 'PUMP', 'PVAC', 'PVBC', 'PWOD', 'PYX', 'PZN', 'PZZA', 'QADA', 'QCRH', 'QDEL', 'QEP', 'QLYS', 'QNST', 'QTRX', 'QTS', 'QTWO', 'QUAD', 'QUOT', 'RAD', 'RAMP', 'RARE', 'RARX', 'RAVN', 'RBB', 'RBBN', 'RBCAA', 'RBNC', 'RC', 'RCII', 'RCKT', 'RCKY', 'RCM', 'RCUS', 'RDFN', 'RDI', 'RDN', 'RDNT', 'RDUS', 'REAL', 'RECN', 'REGI', 'REI', 'REPH', 'REPL', 'RES', 'RESI', 'RETA', 'REV', 'REVG', 'REX', 'REXR', 'RFL', 'RGCO', 'RGEN', 'RGNX', 'RGR', 'RGS', 'RH', 'RHP', 'RICK', 'RIGL', 'RILY', 'RLGT', 'RLGY', 'RLH', 'RLI', 'RLJ', 'RM', 'RMAX', 'RMBI', 'RMBS', 'RMNI', 'RMR', 'RMTI', 'RNET', 'RNST', 'ROAD', 'ROAN', 'ROCK', 'ROG', 'ROIC', 'ROLL', 'ROSE', 'RPD', 'RPT', 'RRBI', 'RRD', 'RRGB', 'RRR', 'RRTS', 'RST', 'RTEC', 'RTIX', 'RTRX', 'RTW', 'RUBI', 'RUBY', 'RUN', 'RUSHA', 'RUSHB', 'RUTH', 'RVI', 'RVNC', 'RVSB', 'RWT', 'RXN', 'RYAM', 'RYI', 'RYTM', 'SAFE', 'SAFM', 'SAFT', 'SAH', 'SAIA', 'SAIC', 'SAIL', 'SALT', 'SAM', 'SAMG', 'SANM', 'SASR', 'SAVE', 'SB', 'SBBP', 'SBBX', 'SBCF', 'SBH', 'SBOW', 'SBRA', 'SBSI', 'SBT', 'SCHL', 'SCHN', 'SCL', 'SCOR', 'SCS', 'SCSC', 'SCU', 'SCVL', 'SCWX', 'SD', 'SDRL', 'SEAS', 'SEM', 'SEMG', 'SENEA', 'SENS', 'SF', 'SFBS', 'SFE', 'SFIX', 'SFL', 'SFNC', 'SFST', 'SGA', 'SGC', 'SGH', 'SGMO', 'SGMS', 'SGRY', 'SHAK', 'SHBI', 'SHEN', 'SHO', 'SHOO', 'SHSP', 'SIBN', 'SIC', 'SIEB', 'SIEN', 'SIG', 'SIGA', 'SIGI', 'SILK', 'SITE', 'SJI', 'SJW', 'SKT', 'SKY', 'SKYW', 'SLAB', 'SLCA', 'SLCT', 'SLDB', 'SLP', 'SM', 'SMBC', 'SMBK', 'SMHI', 'SMMF', 'SMP', 'SMPL', 'SMTC', 'SNBR', 'SNCR', 'SND', 'SNDX', 'SNH', 'SNR', 'SOI', 'SOLY', 'SONA', 'SONM', 'SONO', 'SP', 'SPAR', 'SPFI', 'SPKE', 'SPNE', 'SPOK', 'SPPI', 'SPRO', 'SPSC', 'SPTN', 'SPWH', 'SPWR', 'SPXC', 'SR', 'SRCE', 'SRCI', 'SRDX', 'SRG', 'SRI', 'SRNE', 'SRRK', 'SRT', 'SSB', 'SSD', 'SSP', 'SSTI', 'SSTK', 'SSYS', 'STAA', 'STAG', 'STAR', 'STBA', 'STC', 'STFC', 'STIM', 'STML', 'STMP', 'STNG', 'STOK', 'STRA', 'STRL', 'STRO', 'STRS', 'STXB', 'SUM', 'SUPN', 'SVMK', 'SVRA', 'SWAV', 'SWM', 'SWN', 'SWX', 'SXC', 'SXI', 'SXT', 'SYBT', 'SYBX', 'SYKE', 'SYNA', 'SYNH', 'SYNL', 'SYRS', 'SYX', 'TACO', 'TALO', 'TAST', 'TBBK', 'TBI', 'TBIO', 'TBK', 'TBNK', 'TBPH', 'TCBK', 'TCDA', 'TCFC', 'TCI', 'TCMD', 'TCRR', 'TCS', 'TCX', 'TDOC', 'TDW', 'TECD', 'TELL', 'TEN', 'TENB', 'TERP', 'TESS', 'TEUM', 'TEX', 'TG', 'TGH', 'TGI', 'TGNA', 'TGTX', 'TH', 'THC', 'THFF', 'THOR', 'THR', 'THRM', 'TILE', 'TIPT', 'TISI', 'TITN', 'TIVO', 'TK', 'TLRA', 'TLRD', 'TLYS', 'TMDX', 'TMHC', 'TMP', 'TMST', 'TNAV', 'TNC', 'TNDM', 'TNET', 'TNK', 'TOCA', 'TORC', 'TOWN', 'TPB', 'TPC', 'TPCO', 'TPH', 'TPIC', 'TPRE', 'TPTX', 'TR', 'TRC', 'TREC', 'TREX', 'TRHC', 'TRMK', 'TRNO', 'TRNS', 'TROX', 'TRS', 'TRST', 'TRTN', 'TRTX', 'TRUE', 'TRUP', 'TRWH', 'TRXC', 'TSBK', 'TSC', 'TSE', 'TTEC', 'TTEK', 'TTGT', 'TTI', 'TTMI', 'TTS', 'TUP', 'TUSK', 'TVTY', 'TWI', 'TWIN', 'TWNK', 'TWST', 'TXMD', 'TXRH', 'TYME', 'TYPE', 'TZOO', 'UBA', 'UBFO', 'UBNK', 'UBSI', 'UBX', 'UCBI', 'UCFC', 'UCTT', 'UE', 'UEC', 'UEIC', 'UFCS', 'UFI', 'UFPI', 'UFPT', 'UHT', 'UIHC', 'UIS', 'ULH', 'UMBF', 'UMH', 'UNB', 'UNF', 'UNFI', 'UNIT', 'UNT', 'UNTY', 'UPLD', 'UPWK', 'URGN', 'USCR', 'USLM', 'USNA', 'USPH', 'USWS', 'USX', 'UTL', 'UTMD', 'UUUU', 'UVE', 'UVSP', 'UVV', 'VAC', 'VALU', 'VAPO', 'VBIV', 'VBTX', 'VC', 'VCEL', 'VCRA', 'VCYT', 'VEC', 'VECO', 'VG', 'VGR', 'VHC', 'VHI', 'VIAV', 'VICR', 'VIVO', 'VKTX', 'VLGEA', 'VLY', 'VNCE', 'VNDA', 'VPG', 'VRA', 'VRAY', 'VRCA', 'VREX', 'VRNS', 'VRNT', 'VRRM', 'VRS', 'VRTS', 'VRTU', 'VRTV', 'VSEC', 'VSH', 'VSLR', 'VSTO', 'VVI', 'VYGR', 'WAAS', 'WABC', 'WAFD', 'WAIR', 'WASH', 'WATT', 'WBT', 'WD', 'WDFC', 'WDR', 'WERN', 'WETF', 'WEYS', 'WGO', 'WHD', 'WHG', 'WIFI', 'WINA', 'WING', 'WIRE', 'WK', 'WLDN', 'WLFC', 'WLH', 'WLL', 'WMC', 'WMGI', 'WMK', 'WMS', 'WNC', 'WNEB', 'WOR', 'WOW', 'WPG', 'WRE', 'WRLD', 'WRTC', 'WSBC', 'WSBF', 'WSC', 'WSFS', 'WSR', 'WTBA', 'WTI', 'WTRE', 'WTRH', 'WTS', 'WTTR', 'WVE', 'WW', 'WWW', 'XAN', 'XBIT', 'XELA', 'XENT', 'XERS', 'XFOR', 'XHR', 'XLRN', 'XNCR', 'XOG', 'XON', 'XPER', 'XXII', 'YCBD', 'YELP', 'YETI', 'YEXT', 'YGYI', 'YMAB', 'YORW', 'YRCW', 'ZAGG', 'ZEUS', 'ZGNX', 'ZIOP', 'ZIXI', 'ZUMZ', 'ZUO', 'ZYNE', 'ZYXI']
    
safeties = ['FXF', 'FXA', 'UUP']


Invest = 100000

resolution = Resolution.Daily 
InOut_resolution = Resolution.Hour
returns_resolution = Resolution.Daily

disableSupertrend = True
disableSqueeze = True
disableInAndOut = True

bull = True

inOutLookbackBull = 30
inOutLookbackBear = 5
waitDaysConstant = 1
iniWaitDays = 1
minWaitDays = 1

superTrendPeriod = 1
superTrendMultiple = 3
superTrendUseHA = False

squeezeTrendPeriod = 1
squeezeBBMultiple = 2
squeezeKeltMultiple = 1

max_drawdown = 0.01
drawdown_waitdays = 0
drawdown_lookback = 3
max_alloc = .1
returns_lookback = 2

rebalance = 1
equities_weight = 1

debug = False
dev_mode = False
if dev_mode:
    from AlgorithmImports import *
from collections import deque
from collections.abc import Iterable
from datetime import datetime
from typing import Deque, Dict, List, Union
import numpy as np
import pandas as pd
import operator


class MySuperTrend:
    def __init__(self, period, multiple, movingAverageType=MovingAverageType.Exponential):
        self.Name = "SuperTrend"
        self.Time = datetime.min
        self.Value = 0
        self.multiplier = multiple
        self.atr = AverageTrueRange(period, movingAverageType)
        self.values = deque(maxlen=period)
        self.previousTrailingLowerBand = 0
        self.previousTrailingUpperBand = 0
        self.previousClose = 0
        self.previousTrend = 0
        
    def __repr__(self):
        return "{0} -> IsReady: {1}. Time: {2}. Value: {3}".format(self.Name, self.IsReady, self.Time, self.Value)

    def Update(self, input:TradeBar):
        self.Time = input.EndTime
        self.atr.Update(input)
        superTrend = 0
        currentClose = input.Close
        currentBasicLowerBand = (input.Low + input.High) / 2 - self.multiplier * self.atr.Current.Value
        currentBasicUpperBand = (input.Low + input.High) / 2 + self.multiplier * self.atr.Current.Value

        if self.previousClose > self.previousTrailingLowerBand:
            currentTrailingLowerBand = max(currentBasicLowerBand, self.previousTrailingLowerBand)
        else:
            currentTrailingLowerBand = currentBasicLowerBand

        if self.previousClose < self.previousTrailingUpperBand:
            currentTrailingUpperBand = min(currentBasicUpperBand, self.previousTrailingUpperBand)
        else:
            currentTrailingUpperBand = currentBasicUpperBand

        if currentClose > currentTrailingUpperBand:
            currentTrend = 1
        elif currentClose < currentTrailingLowerBand:
            currentTrend = -1
        else:
            currentTrend = self.previousTrend

        if currentTrend == 1:
            superTrend = currentTrailingLowerBand
        elif currentTrend == -1:
            superTrend = currentTrailingUpperBand
        
        self.previousTrailingLowerBand = currentTrailingLowerBand
        self.previousTrailingUpperBand = currentTrailingUpperBand
        self.previousClose = currentClose
        self.previousTrend = currentTrend

        if not self.atr.IsReady:
            return 0
        
        self.Value = superTrend
        return self.IsReady
    
    @property
    def IsReady(self):
        return self.atr.IsReady and self.Value != 0

class Squeeze:
    def __init__(self, period, squeezeBBMultiple, squeezeKeltMultiple, movingAverageType=MovingAverageType.Exponential):
        '''
        Value = 1 iff "squeezed" else .Value = 0
        '''
        self.Name = "Squeeze"
        self.Time = datetime.min
        self.Value = 0
        self.bb = BollingerBands(period, squeezeBBMultiple, movingAverageType)
        self.kelt = KeltnerChannels(period, squeezeKeltMultiple, movingAverageType)

    def __repr__(self):
        return "{0} -> IsReady: {1}. Time: {2}. Value: {3}".format(self.Name, self.IsReady, self.Time, self.Value)

    def Update(self, input:TradeBar):
        self.Time = input.EndTime
        self.kelt.Update(input)
        self.bb.Update(input.EndTime, input.Close)
        isSqueeze = self.bb.UpperBand.Current.Value > self.kelt.UpperBand.Current.Value
        self.Value = int(isSqueeze)
        return self.IsReady 

    @property
    def IsReady(self):
        return self.kelt.IsReady and self.bb.IsReady

class Drawdown:
    def __init__(self, period:int):
        self.values = deque(maxlen=period)
        self.Value = 0

    def Update(self, input:Union[TradeBar, float]):
        if isinstance(input, float):
            self.values.append(input)
        else:
            self.values.append(input.Close)
       
        cum_returns = (1 + pd.Series(self.values)).cumprod()
        self.Value = 1 - cum_returns.div(cum_returns.cummax()).iloc[-1]
        return self.IsReady
        
    @property
    def IsReady(self):
        return len(self.values) == self.values.maxlen

class InAndOut:
    def __init__(self, algo:QCAlgorithm, InOut_resolution, symbols:List[str], period:int, iniWaitDays, minWaitDays, waitDaysConst, bull=True):
        self.Time = datetime.min
        
        self.period = period
        self.iniWaitDays = iniWaitDays
        self.minWaitDays = minWaitDays
        self.waitDaysConst = waitDaysConst
        self.bull = bull

        (self.market, self.silver, self.gold, self.utility, 
            self.industrial, self.safe, self.risk, self.debt_short, 
            self.debt_inflation, self.metal, self.input, self.cash) = symbols

        self.bull_signal_indices = [self.industrial, self.metal, self.input]
        self.history: dict[Symbol, Deque[float]] = {}
        history_df = algo.History(symbols, period, resolution)

        for symbol in symbols:
            if symbol in history_df and len(history_df[symbol]) > 0:
                self.history[symbol] = deque(history_df[symbol]['close'], maxlen=period)
            else:
                self.history[symbol] = deque(maxlen=period)

        self.wait_days = 0

    def Update(self, input:Slice):
        self.Time = input.Time

        for symbol, history in self.history.items():
            if input.Bars.ContainsKey(symbol):
                history.append(input[symbol].Close)
        
    def is_bullish(self):
        history_dict = {symbol: pd.Series(data) for symbol, data in self.history.items()}

        cust_returns_dict: dict[Union[Symbol, str], pd.Series] = {}
        for symbol in history_dict:
            if len(history_dict[symbol]) != self.period:
                return False, 0
        
            hist_series = history_dict[symbol]
            cust_returns_dict[symbol] = (hist_series / hist_series.rolling(5, center=True).mean().shift(10)).dropna() - 1
            history_dict[symbol] = history_dict[symbol][-len(cust_returns_dict[symbol]):]

        gold_min_silver = 'gold_min_silver'
        industrial_min_utility = 'industrial_min_utility'
        risk_min_safe = 'risk_min_safe'
        cash_inverse = 'cash_inverse'

        cust_returns_dict[gold_min_silver] = cust_returns_dict[self.gold] - cust_returns_dict[self.silver]
        cust_returns_dict[industrial_min_utility] = cust_returns_dict[self.industrial] - cust_returns_dict[self.utility]
        cust_returns_dict[risk_min_safe] = cust_returns_dict[self.risk] - cust_returns_dict[self.safe]
        cust_returns_dict[cash_inverse] = -1 * cust_returns_dict[self.cash]

        is_extreme_returns_dict: dict[Union[Symbol, str], bool] = {}
        for symbol, returns in cust_returns_dict.items():
            is_extreme_returns_dict[symbol] = returns.iloc[-1] < np.percentile(returns, 1)

        inflation = 'inflation'
        history_dict[inflation] = cust_returns_dict[self.debt_short] - cust_returns_dict[self.debt_inflation]
        
        isabovemedian_dict = {
            symbol: (series.iloc[-1] > series.median()) for symbol, series in history_dict.items()
        }

        interest_expected = 'interest_expected'

        if is_extreme_returns_dict[self.debt_short] and isabovemedian_dict[self.metal] and isabovemedian_dict[self.input]:
            is_extreme_returns_dict[interest_expected] = False
        else:
            is_extreme_returns_dict[interest_expected] = is_extreme_returns_dict[self.debt_short]

        gold_min_silver_adj = 'gold_min_silver_adj'
    
        if is_extreme_returns_dict[gold_min_silver] and isabovemedian_dict[inflation]:
            is_extreme_returns_dict[gold_min_silver_adj] = False
        else:
            is_extreme_returns_dict[gold_min_silver_adj] = is_extreme_returns_dict[gold_min_silver]
        
        def wait_days_helper(symbol0, symbol1):
            series0 = cust_returns_dict[symbol0]
            series1 = cust_returns_dict[symbol1]
            if series0.iloc[-1] > 0 and series1.iloc[-1] < 0 and series1.iloc[-2] > 0:
                return self.iniWaitDays
            else:
                return 1

        self.wait_days = int(
            max(
                self.wait_days/2,
                self.iniWaitDays * max (
                    1, 
                    wait_days_helper(self.gold, self.silver), 
                    wait_days_helper(self.utility, self.industrial), 
                    wait_days_helper(self.safe, self.risk)
                )
            )
        )

        signals = self.bull_signal_indices + [gold_min_silver_adj, industrial_min_utility, risk_min_safe, cash_inverse]
        
        bullish = any([is_extreme_returns_dict[signal] for signal in signals])
        return bullish, min(self.minWaitDays, self.wait_days)

    def is_bearish(self):
        market_returns = pd.Series(self.history[self.market]).pct_change().dropna()
        volatililty = .6 * np.sqrt(252) * np.log1p(market_returns).std()
        returns_lookback = int(min(
            (1-volatililty)*self.waitDaysConst,
            self.period
        ))
        wait_days = int(volatililty * self.waitDaysConst)
        
        signals = [self.silver, self.gold, self.industrial, self.utility, self.metal, self.cash]

        returns = {}
        for signal in signals:
            data = self.history[signal]
            if len(data) < returns_lookback:
                return False, 0
            returns[signal] = pd.Series(data).pct_change(returns_lookback).iloc[-1]

        def compare(symbol0, symbol1):
            return returns[symbol0] < returns[symbol1]
        
        compares = compare(self.silver, self.gold) and compare(self.industrial, self.utility) and compare(self.metal, self.cash)
        return compares, wait_days            

    def minmax(self, n1, min_val, max_val):
        return max(min(n1, min_val), max_val)

    def get_signal(self):
        if self.bull:
            return self.is_bullish()
        else:
            return self.is_bearish()

class ReturnsManager:
    def __init__(self, algo, period, returns_resolution, max_drawdown, drawdown_lookback, max_alloc):
        self.algo = algo
        self.period = period
        self.drawdown_lookback = drawdown_lookback
    
        self.daily_returns_dict: Dict[Symbol, RateOfChange] = {}
        self.returns_dict: Dict[Symbol, RateOfChange] = {}
        self.dd = Drawdown(self.drawdown_lookback)

        self.weights_dict: Dict[Symbol, float] = {}

        self.max_drawdown = max_drawdown
        self.max_alloc = max_alloc
        
    def Update(self, input:Slice):
        portfolio_returns_cross_section = 0
        
        for symbol in self.returns_dict: 
            if input.Bars.ContainsKey(symbol):
                daily_returns = self.daily_returns_dict[symbol]
                daily_returns.Update(input.Time, input[symbol].Close)
                self.returns_dict[symbol].Update(input.Time, input[symbol].Close)
                
                if symbol in self.weights_dict and daily_returns.IsReady:
                    item_returns = self.weights_dict[symbol] * daily_returns.Current.Value
                    portfolio_returns_cross_section += item_returns

        if portfolio_returns_cross_section:
            self.dd.Update(portfolio_returns_cross_section)

    def UpdateWeights(self):
        total_weight = sum(
            returns.Current.Value 
            for returns in self.returns_dict.values() 
            if returns.IsReady
        )

        if not total_weight:
            return {}

        self.weights_dict = {
            symbol: min(returns.Current.Value / total_weight, self.max_alloc)
                for symbol, returns in self.returns_dict.items()
        }
        return self.weights_dict

    def GetWeights(self):
        return self.weights_dict

    def IsSell(self):
        return self.dd.Value > self.max_drawdown

    @property
    def IsReady(self):
        return np.any([returns.IsReady for symbol, returns in self.returns_dict.items()]) and len(self.weights_dict) > 0

    def WarmUp(self, symbols:Union[Symbol, None]):
        if not isinstance(symbols, Iterable):
            symbols = [symbols] 

        hist = self.algo.History(symbols, self.period, self.resolution)
        for symbol in symbols:
            if symbol not in hist.index or not len(hist.loc[symbol]):
                continue
            closes = hist.loc[symbol]['close']
            for dt, close in closes.iteritems():
                self.daily_returns_dict[symbol].Update(dt, close)
                self.returns_dict[symbol].Update(dt, close)

    def AddSecurity(self, symbol:Symbol):
        if symbol not in self.returns_dict:
            self.daily_returns_dict[symbol] = RateOfChange(1)
            self.returns_dict[symbol] = RateOfChange(self.period)


class AdaptableRedSnake(QCAlgorithm):
    def load_configs_and_indicators(self):
        
        self.Cash = Invest

        index_tickers = [market, silver, gold, utility, industrial, safe, risk, debt_short, debt_inflation, metal, inp, cash]
        self.indices = [
            self.AddEquity(ticker, resolution).Symbol for ticker in index_tickers
        ]

        inOutLookback = inOutLookbackBull if bull else inOutLookbackBear
        self.inandout = InAndOut(self, resolution, self.indices, inOutLookback, iniWaitDays, minWaitDays, waitDaysConstant, bull)
        self.returnsmanager = ReturnsManager(self, returns_lookback, resolution, max_drawdown, drawdown_lookback, max_alloc)

        self.equities = [
            self.AddEquity(ticker, resolution).Symbol for ticker in equities
        ]
        
        for equity in self.equities:
            self.Securities[equity].SetDataNormalizationMode(DataNormalizationMode.Raw)
    
        self.safeties = [
            self.AddEquity(ticker, resolution).Symbol for ticker in safeties
        ]
        
        for safety in self.safeties:
            self.Securities[safety].SetDataNormalizationMode(DataNormalizationMode.Raw)
        
        self.symbolData = {
            symbol: SymbolData(self, symbol, resolution,
                superTrendPeriod, superTrendMultiple, 
                squeezeTrendPeriod, squeezeBBMultiple, 
                squeezeKeltMultiple, superTrendUseHA)
                for symbol in self.equities + self.safeties
        }

        self.universe = self.equities
        self.UniverseSettings.DataNormalizationMode = DataNormalizationMode.Raw
            
        self.next_reentry = self.Time
        self.was_bull = False
        self.inout_signal = False
        self.inout_waitdays = 0

        for symbol in self.equities + self.safeties:
            self.returnsmanager.AddSecurity(symbol)

        self.SetWarmUp(max(
            inOutLookbackBear, inOutLookbackBull, returns_lookback
        ), InOut_resolution)
        
        self.SetWarmUp(max(
            superTrendPeriod, squeezeTrendPeriod
        ), resolution)

    def Initialize(self):
        self.load_configs_and_indicators()
        
        self.market = market
        self.SetBenchmark(self.market)
        self.SetBrokerageModel(BrokerageName.InteractiveBrokersBrokerage)



        self.SetStartDate(2020, 1, 1)
        self.SetCash(Invest) 


        self.days_count = 0
        self.curr_day = -1
        self.init_rebalance = True

    def Print(self, msg):
        if debug:
            self.Debug(msg)

    def OnData(self, data:Slice):
        for symbol, symbolData in self.symbolData.items():
            if data.Bars.ContainsKey(symbol):
                symbolData.Update(data[symbol])
        
        if self.was_bull and not self.IsWarmingUp:
            self.rebalance(data)
        
        if self.curr_day == self.Time.day:
            return 
        self.curr_day = self.Time.day


        if not any([data.Bars.ContainsKey(symbol) for symbol in self.equities]):
            return

        self.days_count += 1
        self.inandout.Update(data)
        self.returnsmanager.Update(data)
        if self.init_rebalance or self.days_count % rebalance == 0:
            self.init_rebalance = False
            self.returnsmanager.UpdateWeights()
            self.inout_signal, self.inout_waitdays = self.inandout.get_signal()
        
        if self.IsWarmingUp:
            return

        if self.returnsmanager.IsSell():
            self.Liquidate()
            self.next_reentry = self.Time + timedelta(days=drawdown_waitdays)
        elif (self.inout_signal or disableInAndOut):
            debug and self.Print('Bull Condition Reached')
            if not self.was_bull and self.Time >= self.next_reentry:
                self.Print('Going Bull')
                self.go_bull()
                self.was_bull = True
        elif self.was_bull:
            self.Print(f'Going Bear:')
            self.go_bear()
            self.was_bull = False
            self.next_reentry = self.Time + timedelta(days=self.inout_waitdays)
        
        self.PlotSeries()
    
    def PlotSeries(self): 
        self.Plot('BullBear', 'bull=1,bear=0', int(self.was_bull))
 
    def go_bear(self):
        if self.IsWarmingUp:
            return
        self.Liquidate()

        self.universe = self.safeties
        self.UniverseSettings.DataNormalizationMode = DataNormalizationMode.Raw
        
        for symbol in self.safeties:
            self.SetHoldings(symbol, equities_weight/len(self.safeties))
        self.was_bull = False

    def go_bull(self):
        if self.IsWarmingUp:
            return
        self.Liquidate()
        for symbol, symbolData in self.symbolData.items():
            if symbolData.IsBuy(self.Securities[symbol].Price):
                weight = self.returnsmanager.GetWeights().get(symbol, 0)
                if weight:
                    self.SetHoldings(symbol, weight * equities_weight)

    def rebalance(self, data:Slice):
        bought = []
        for symbol, symbolData in self.symbolData.items():
            if symbol not in self.universe:
                continue
            isbuy = symbolData.IsBuy(self.Securities[symbol].Price)
            if not isbuy:
                self.Liquidate(symbol)
            elif not self.Portfolio[symbol].Invested:
                weight = self.returnsmanager.GetWeights().get(symbol, 0)
                self.SetHoldings(symbol, weight * equities_weight)
                bought.append(symbol)

class SymbolData:
    def __init__(self, algo:QCAlgorithm, symbol, resolution, periodST, multipleST, periodSQ, BBmultipleSQ, KELTmultipleSQ, useHA):
        self.symbol = symbol
        self.supertrend = MySuperTrend(periodST, multipleST)
        self.squeeze = Squeeze(periodSQ, BBmultipleSQ, KELTmultipleSQ)
        
        self.algo = algo

        self.useHA = useHA
        if useHA:
            self.ha = HeikinAshi(symbol)

    def Update(self, input:TradeBar):
        if self.useHA:
            self.ha.Update(input)
            if self.ha.IsReady:
                haBar = TradeBar(self.algo.Time, self.symbol, 
                    self.ha.Open.Current.Value, self.ha.High.Current.Value, 
                    self.ha.Low.Current.Value, self.ha.Close.Current.Value, self.ha.Volume.Current.Value)
                self.supertrend.Update(haBar)
        else:
            self.supertrend.Update(input)

        self.squeeze.Update(input)

    def IsBuy(self, price):
        return (self.squeeze.Value or disableSqueeze) or (price > self.supertrend.Value or disableSupertrend)