Overall Statistics |
Total Trades 359 Average Win 1.47% Average Loss -1.51% Compounding Annual Return 12.739% Drawdown 51.700% Expectancy 0.276 Net Profit 81.704% Sharpe Ratio 0.496 Loss Rate 35% Win Rate 65% Profit-Loss Ratio 0.97 Alpha 0.031 Beta 1.009 Annual Standard Deviation 0.273 Annual Variance 0.074 Information Ratio 0.131 Tracking Error 0.245 Treynor Ratio 0.134 Total Fees $359.00 |
//Copyright Warren Harding 2016 //Use entirely at your own risk. //Custom algorithm development: warrencharding@yahoo.com. //Do not remove this copyright notice. using System; using System.Collections.Generic; using System.Collections.Concurrent; using QuantConnect.Data.Market; using QuantConnect.Orders; using QuantConnect.Orders.Fees; using QuantConnect.Orders.Fills; using QuantConnect.Orders.Slippage; using QuantConnect.Securities; namespace QuantConnect { public class Algo4 : QCAlgorithm { //You can adjust this first set to optimize. decimal lowerBandRatio = 0.975m; decimal upperBandRatio = 1.025m; decimal rsiBuyCutoff=50; decimal maximumTrade=1000000; decimal minimumTrade = 500m; int maPeriod=20; int rsiPeriod=5; //Your broker is going to hate you if you set these too low as it will result in large amounts of unfilled //order cancellations. It bogs down LEAN as well. int barsToHoldBuyOrdersFor=0; int barsToHoldSellOrdersFor=0; Resolution resolution = Resolution.Daily; decimal ratioOfDollarVolumeForMaxTrade; List<StockData> stockDatas = new List<StockData>(); List<OrderTicketWrapper> buyOrders=new List<OrderTicketWrapper>(); List<OrderTicketWrapper> sellOrders=new List<OrderTicketWrapper>(); public override void Initialize() { SetStartDate(2012, 1, 1); SetEndDate(2017, 1, 1); SetCash(100000); //s&p 500. string tickersString ="CHK,DO,ENDP,MUR,SWN,FCX,RIG,NRG,MRO,NEM,RRC,CF,MU,APA,VRTX,FOSL,APC,WDC,DVN,MOS,FTR,MNK,VIAB,WYNN,UAL,FSLR,TSO,NFX,HP,HES,NAVI,AAL,SIG,ALXN,STX,SWKS,MPC,NOV,URI,NBL,QRVO,WMB,HOG,JWN,DAL,OI,PXD,OKE,MYL,NVDA,RCL,CXO,TGNA,COG,XEC,HPE,ETFC,EOG,KSS,GPS,REGN,HRB,HAL,AVGO,PRGO,BHI,UA,M,ADS,CSC,URBN,KMI,AA,COP,PYPL,KORS,LUV,EQT,VLO,FTI,FMC,DISCA,JCI,LNC,SE,ALK,NUE,VMC,AMG,AES,LEN,CNC,SPLS,WRK,BWA,HAR,TDC,CBG,GT,R,KMX,HST,ZION,ALB,AN,TIF,RF,CBS,CMG,NFLX,MLM,DISCK,SCHW,LM,EXPE,BBBY,DHI,COH,VRSN,ILMN,FLS,DLPH,JNPR,PHM,NTAP,MAR,FTV,CFG,CHTR,TRIP,NWSA,BAC,BEN,AMAT,AGN,MET,YHOO,HCP,MS,ADSK,WHR,HPQ,WY,BIIB,KEY,VTR,LYB,CMA,VFC,LUK,LRCX,DLR,DG,LB,CELG,AIV,RL,PVH,AYI,MCK,ULTA,IVZ,ATVI,MJN,CCL,IR,SNI,IPG,FITB,FFIV,UNM,HCA,BBY,HBAN,SYF,SLG,ESS,KR,DLTR,DUK,FE,BMY,TAP,KSU,O,EQIX,LVLT,C,GRMN,MCHP,GWW,PWR,PDCO,EXR,MAS,CNP,SYMC,FLR,CRM,BF-B,STI,SCG,HCN,CSX,FOXA,IP,HOLX,VNO,PLD,EQR,KLAC,GGP,WFC,AKAM,UHS,UDR,CTL,PKI,NI,JEC,GPN,NWL,BSX,MDLZ,SEE,CTSH,SRCL,ADI,SRE,IRM,COF,PBI,AAPL,DOV,PRU,CMI,PNR,GM,GS,WFM,MAT,FBHS,HBI,EA,CTXS,PEG,JBHT,PCAR,RHT,AVB,OXY,STT,PSA,EMN,AMP,PFG,ANTM,WLTW,CCE,MAC,LNT,NSC,KIM,F,MON,XYL,RAI,TSCO,MNST,HRL,PPL,EW,LKQ,MTD,ETR,AZO,EBAY,KHC,FAST,DTE,HIG,AWK,NKE,SPGI,SYK,SLB,TSS,NEE,GILD,XRX,BLK,PNC,INTC,EXC,CCI,CERN,AEE,ETN,XRAY,ACN,FL,AAP,MCO,ESRX,ABT,CPB,ALLE,GPC,BK,CAH,GIS,LEG,XEL,WEC,DD,DGX,TXN,CMS,WAT,BXP,UNP,QCOM,ADM,WYN,FRT,ABC,AXP,AMT,HAS,NTRS,TDG,SPG,CVX,FDX,TWX,CHRW,XLNX,CA,RHI,PBCT,BAX,PNW,ES,T,EMR,CI,AMGN,DNB,TMO,DRI,BBT,CAT,ROK,MHK,WBA,TXT,ED,PSX,CME,ROST,PH,EIX,TSN,A,TGT,ZBH,HOT,PCG,AEP,LOW,TROW,PPG,PCLN,D,SHW,STZ,XL,CAG,DVA,XOM,MTB,HSIC,ABBV,BA,ADBE,ROP,ITW,HRS,PX,VZ,MRK,LH,PG,VAR,PM,BCR,L,SYY,LLY,HSY,SJM,TEL,DFS,MSFT,BDX,WU,FB,CSCO,UTX,AIZ,APD,NDAQ,DE,SO,JPM,NLSN,AET,OMC,FLIR,ORCL,UNH,FISV,IBM,EXPD,HD,AMZN,DHR,CMCSA,DOW,EFX,ISRG,LLL,FIS,MO,HON,HUM,COST,INTU,PAYX,SBUX,MKC,COL,CHD,CTAS,ECL,ZTS,AIG,PFE,AVY,PGR,USB,AME,BLL,APH,K,CVS,SNA,CINF,YUM,GD,TJX,EL,MDT,ORLY,WMT,DPS,ADP,MA,GE,GLW,ICE,GOOGL,CLX,SWK,KMB,GOOG,AFL,TRV,AON,RSG,VRSK,BRK-B,IFF,MSI,RTN,DIS,MMC,LMT,KO,STJ,TMK,V,CL,NOC,PEP,MCD,MMM,WM,ALL,UPS,JNJ,LLTC"; //10 rows volatiles //string tickersString="CDII,STEM,XCOM,ENRJ,SKLN,ASTI,ICLD,PSG,PVCT,SPU,NYMX,NAVB,THLD,CCCR,BAS,IKGH,RCPI,GBR,AMDA,DAKP,COSI,EGLE,ETAK,MBII,ESEA,LPTN,NVFY,XGTI,MBLX,FES,AREX,DRYS,GBSN,ATEC,TLOG,BCEI,UAMY,ESNC,DELT,HEB,ETRM,CRK,URRE,ADGE,YRD,GTXI,JNUG,ATLS,NEOT,CYCC,SNSS,PHMD,JDST,TPLM,REN,YECO,IDXG,TOPS,ORIG,IPDN,HTBX,BNSO,CUR,SVBL,SAEX,GLBS,IFMI,RLJE,NSPR,CIDM,SKYS,CLCD,MCUR,TSRI,PTX,STAF,IMUC,VII,MPET,LEDS,NAK,TRCH,LNTH,SPHS,CLRB,IFON,THM,PQ,MGN,NIHD,BIOC,NFEC,TRX,SINO,IGC,NUGT,GBIM,SORL,PULM,AUPH,TNXP,CIE,DUST,MSTX,SGY,MRNS,OGXI,HNR,APPS,ROKA,RNVA,CPRX,CXW,GLRI,FNCX,IMNP,TBIO,KPTI,PTI,FSI,KOOL,AXU,NETE,NVCN,JAGX,BVX,GSV,HPJ,CRMD,MIFI,NWBO,ONTX,OPGN,FATE,CDTI,ANY,PI,PZG,CLVS,GEO,KMPH,CBAY,APRI,PACD,ACIA,AAU,ELMD,WATT,BAA,LEI,CGNT,ASTC,CRBP,RESN,VRS,AVXS,MEET,SCYX,TGD,TGC,BZUN,EBIO,EMXX,GSAT,EARS,MGH,GMAN,DMTX,FELP,KURA,TAT,MDVX,WGA,AUMN,INVT,GALT,MOMO,ATRS,WAC,AMRS,VHI,VGZ,ADMP,LIVE,CNXR,DWTI,ACPW,CHNR,TWLO,OPTT,OCUL,NTLA,PSIX,BGI,RADA,CERU,CBIO,CETX,ADVM,UWTI,RBCN,SMIT,BLRX,EMAN,CCXI,ZYNE,RGNX,RTTR,COLL,LIFE,RIGL,CBYL,TKAI,NRP,MLNK,TRIL,VHC,CRC,EVLV,BCRX,BONT,PTN,IMN,AVGR,NADL,LEE,FENX,PFMT,DVAX,DRNA,MNKD,GEVO,MCEP,CTRV,GLF,ROSG,XNY,BSTG,LOV,AQXP,CWEI,LGCY,HK,VMEM,LABU,QHC,GFA,VNR,LABD,MUX,I,NLST,WYY,FSAM,EVOK,SNMX,LUNA,DGAZ,PXLW,GEN,XRA,HEAR,NEON,PTLA,BIOD,TPB,ISNS,LEJU,FNBC,VSAR,ARLZ,SCON,LPCN,TBRA,NEOS,IMMU,CLD,AFMD,UGAZ,VYGR,XXII,AST,NOG,STRP,NVTA,ARGS,TRXC,OREX,HIIQ,SYMX,ORPN,PRKR,BRZU,ASM,ARWR,WLB,NURO,MGT,DNR,NK,GORO,BLDP,RETA,EXK,RTK,UEC,JONE,XBIT,CGIX,EGLT,EVRI,VNDA,UVXY,VUZI,GST,OVAS,TVIX,LODE,KGJI,CLNT,SQNS,NERV,CXRX,VTAE,HUSA,DGLY,HOS,CBR,EDIT,RYI,CVEO,EPZM,GALE,BREW,FSM,ALIM"; string[] tickers = tickersString.Split(new string[1] { "," }, StringSplitOptions.RemoveEmptyEntries); foreach (string ticker in tickers) { AddSecurity(SecurityType.Equity,ticker,resolution); StockData stockData=new StockData(ticker,maPeriod,rsiPeriod); stockDatas.Add(stockData); } foreach (Security s in Securities.Values) { s.FeeModel=new CustomFeeModel(); } //Be careful adjusting this next one, too high of a setting will result in unrealistically large //purchases being made with no regards for slippage. if (resolution == Resolution.Daily) { ratioOfDollarVolumeForMaxTrade = 1m / 6.5m / 60m; } else if (resolution==Resolution.Minute) { ratioOfDollarVolumeForMaxTrade = .25m; } } public void OnData(TradeBars data) { UpdateIndicators(data); Buy(data); Sell(data); } public void UpdateIndicators(TradeBars data) { foreach (StockData stockData in stockDatas) { if (data.ContainsKey(stockData.Ticker)) { stockData.Update(data[stockData.Ticker].Time,data[stockData.Ticker].Close); } } } public void Buy(TradeBars data) { CancelExpiredOrders(buyOrders,barsToHoldBuyOrdersFor); int quantity = 0; decimal buyPrice; TradeBar bar; string ticker; var stockDatas2 = from stockData in stockDatas where stockData.Change > 0.0m where (1 - stockData.AverageMinusCloseRatio) < lowerBandRatio where stockData.RSI>rsiBuyCutoff //orderby stockData.Change descending orderby stockData.Change descending select stockData; foreach (StockData stockData in stockDatas2) { ticker=stockData.Ticker; if (!Portfolio[ticker].HoldStock && data.ContainsKey(ticker) && stockData.EMA.IsReady) { bar=data[ticker]; buyPrice=stockData.EMA*lowerBandRatio; if (bar.Close<buyPrice) { quantity=SizePosition(bar); if (quantity > 0) { buyPrice=bar.Close; OrderTicketWrapper orderTicketWrapper=new OrderTicketWrapper(); orderTicketWrapper.orderTicket = LimitOrder(bar.Symbol, quantity,buyPrice); orderTicketWrapper.price=buyPrice; buyOrders.Add(orderTicketWrapper); } } } } foreach (OrderTicketWrapper orderTickerWrapper in buyOrders) { orderTickerWrapper.count++; } } public void Sell(TradeBars data) { CancelExpiredOrders(sellOrders,barsToHoldSellOrdersFor); decimal sellPrice; TradeBar bar; string ticker; foreach (StockData stockData in stockDatas) { ticker=stockData.Ticker; if (Portfolio[ticker].Quantity > 0 && data.ContainsKey(ticker) && stockData.EMA.IsReady) { bar = data[ticker]; sellPrice = stockData.EMA * upperBandRatio; if (bar.Close > sellPrice) { sellPrice = bar.Close; OrderTicketWrapper orderTicketWrapper = new OrderTicketWrapper(); orderTicketWrapper.orderTicket = LimitOrder(ticker, -Portfolio[ticker].Quantity, sellPrice); orderTicketWrapper.price=sellPrice; sellOrders.Add(orderTicketWrapper); } } } foreach (OrderTicketWrapper orderTickerWrapper in sellOrders) { orderTickerWrapper.count++; } } static void CancelExpiredOrders(List<OrderTicketWrapper> orderTickerWrappers,int barsToHoldOrdersFor) { foreach (OrderTicketWrapper orderTickerWrapper in orderTickerWrappers) { if (orderTickerWrapper.count>barsToHoldOrdersFor) { orderTickerWrapper.orderTicket.Cancel(); } } orderTickerWrappers.RemoveAll(x=>x.orderTicket.Status==OrderStatus.Filled | x.orderTicket.Status==OrderStatus.Canceled); } static decimal SumBuyOrders(List<OrderTicketWrapper> buyOrders) { decimal sum=0; foreach (OrderTicketWrapper orderTickerWrapper in buyOrders) { sum += orderTickerWrapper.orderTicket.Quantity * orderTickerWrapper.price; } return sum; } int SizePosition(TradeBar bar) { decimal maxTrade=bar.Close*bar.Volume*ratioOfDollarVolumeForMaxTrade; if (maxTrade>maximumTrade) { maxTrade=maximumTrade; } int quantity =(int)Math.Floor(Math.Min(Portfolio.Cash-SumBuyOrders(buyOrders), maxTrade) / bar.Close); quantity = RoundLot(quantity); if (quantity * bar.Close < minimumTrade) { return 0; } return quantity; } static int RoundLot(int inOddLotQuantity) { decimal inQuantity = (decimal)inOddLotQuantity; if (inQuantity > 2000000) { decimal small = inQuantity / 1000000; small = Math.Floor(small); return (int)(small * 1000000); } if (inQuantity > 200000) { decimal small = inQuantity / 100000; small = Math.Floor(small); return (int)(small * 100000); } if (inQuantity > 20000) { decimal small = inQuantity / 10000; small = Math.Floor(small); return (int)(small * 10000); } if (inQuantity > 2000) { decimal small = inQuantity / 1000; small = Math.Floor(small); return (int)(small * 1000); } if (inQuantity > 200) { decimal small = inQuantity / 100; small = Math.Floor(small); return (int)(small * 100); } if (inQuantity > 20) { decimal small = inQuantity / 10; small = Math.Floor(small); return (int)(small * 10); } return inOddLotQuantity; } class OrderTicketWrapper { public OrderTicket orderTicket; public int count=0; public decimal price; } class StockData { public StockData(string ticker,int maPeriod,int rsiPeriod) { Ticker=ticker; EMA = new ExponentialMovingAverage(maPeriod); RSI = new RelativeStrengthIndex(rsiPeriod); } public string Ticker; public ExponentialMovingAverage EMA; public RelativeStrengthIndex RSI; public decimal Price; public decimal AverageMinusCloseRatio; public decimal Change; public decimal PreviousValue=0; public bool Update(DateTime time, decimal value) { bool ready=EMA.Update(time, value) && RSI.Update(time, value); if (ready) { AverageMinusCloseRatio=(EMA - value) / value; Price=value; if (PreviousValue!=0) { Change=(value-PreviousValue)/PreviousValue; } PreviousValue=value; } return ready; } } public class CustomFeeModel : IFeeModel { public decimal GetOrderFee(Security security, Order order) { return 1; } } } }