/* Seasonal Soybean Strategy per Katsanos article EL code */ using System; using System.Collections.Generic; using System.Text; using System.Drawing; using WealthLab; using WealthLab.Indicators;namespace WealthLab.Strategies { public class MyStrategy : WealthScript { StrategyParameter D1DXY; StrategyParameter D2SNL; StrategyParameter LRSDXYSELL; StrategyParameter LRSNLSELL; StrategyParameter MASELL; StrategyParameter MASNL; StrategyParameter MADXY; StrategyParameter chnlLength; public MyStrategy() { D1DXY = CreateParameter("DX LRSlope Period", 25, 10, 50, 1); D2SNL = CreateParameter("Snl LRSlope Period", 12, 5, 25, 1); LRSDXYSELL = CreateParameter("DX LRSlope", 0.3, 0.1, 0.8, 0.1); LRSNLSELL = CreateParameter("Snl LRSlope", -0.8, -1.2, -0.5, 0.1 ); MASELL = CreateParameter("Soybean EMA Period", 15, 5, 25, 1); MASNL = CreateParameter("Snl EMA Period", 15, 5, 25, 1); MADXY = CreateParameter("DX MA Period", 50, 20, 100, 5); chnlLength = CreateParameter("Channel Period", 4, 2, 20, 2); } // ROC of LR Line divided by its period private double LRLineROCdivPeriod(int bar, DataSeries ds, int period) { int n = bar - period + 1; double y1 = LinearRegLine(ds, n, bar, bar); double y2 = LinearRegLine(ds, n, bar, n); double per = period; return 100 * ( y1 / y2 - 1d ) / per; } protected override void Execute() { HideVolume(); int buyMonth = 9; int sellMonth = 6; // Access external data Bars dxy = GetExternalSymbol("DXY", true); Bars snl = GetExternalSymbol("SNL", true); // Create and plot indicators DataSeries channelHiPlus2 = (Highest.Series(Close >> 1, chnlLength.ValueInt) + 2d); DataSeries channelLoMinus2 = (Lowest.Series(Close >> 1, chnlLength.ValueInt) - 2d); PlotSeries(PricePane, channelHiPlus2, Color.Blue, LineStyle.Dashed, 1); PlotSeries(PricePane, channelLoMinus2, Color.Brown, LineStyle.Dashed, 1); DataSeries rs = EMA.Series(Close/snl.Close, 3, EMACalculation.Modern); DataSeries LRSNL = new DataSeries(Bars, "Seasonal Avg Change(" + D2SNL.ValueInt + ")"); for (int bar = D2SNL.ValueInt; bar < Bars.Count; bar++) LRSNLbar = LRLineROCdivPeriod(bar, rs, D2SNL.ValueInt); DataSeries LRSDXY = new DataSeries(Bars, "LRSDXY"); for (int bar = D1DXY.ValueInt; bar < Bars.Count; bar++) LRSDXYbar = LRLineROCdivPeriod(bar, dxy.Close, D1DXY.ValueInt); ChartPane lrPane = CreatePane(40, true, true); PlotSeries(lrPane, LRSNL, Color.Green, LineStyle.Solid, 2); PlotSeries(lrPane, LRSDXY, Color.Black, LineStyle.Solid, 2); DataSeries ema = EMA.Series(Close, MASELL.ValueInt, EMACalculation.Modern); PlotSeries(PricePane, ema, Color.Green, LineStyle.Solid, 1); DataSeries emaDXY = EMA.Series(dxy.Close, MADXY.ValueInt, EMACalculation.Modern); DataSeries emaSNL = EMA.Series(snl.Close, MASNL.ValueInt, EMACalculation.Modern); // Trading Strategy logic for(int bar = 2 * GetTradingLoopStartBar(50); bar < Bars.Count; bar++) { int month = Datebar.Month; bool seasonalBuy = month < sellMonth || month > buyMonth; bool seasonalShort = month > sellMonth && month < buyMonth; bool buy = seasonalBuy && LRSDXYbar < LRSDXYSELL.Value && Closebar > channelHiPlus2bar && LRSNLbar > LRSNLSELL.Value; bool sell = seasonalShort && Closebar < channelLoMinus2bar && LRSDXYbar > -LRSDXYSELL.Value && LRSNLbar < -LRSNLSELL.Value; if (!IsLastPositionActive) { if (buy) BuyAtMarket(bar + 1); else if (sell) ShortAtMarket(bar + 1); } else { Position p = LastPosition; if ( bar - p.EntryBar < 1 ) continue; else if (p.PositionType == PositionType.Long) { if (sell) { ExitAtMarket(bar + 1, p, "Reverse"); ShortAtMarket(bar + 1); } else if( Closebar < emabar ) { if ( LRSNLbar < LRSNLSELL.Value ) ExitAtMarket(bar + 1, p, "L_exit RS"); else if( emaDXYbar > emaDXYbar - 1 && LRSDXYbar > LRSDXYSELL.Value ) ExitAtMarket(bar + 1, p, "L_exit DXY"); } } else // Position is short { if (buy) { ExitAtMarket(bar + 1, p, "Reverse"); BuyAtMarket(bar + 1); } else if( Closebar > emabar ) { if ( LRSNLbar > -LRSNLSELL.Value ) ExitAtMarket(bar + 1, p, "S_exit RS: " + LRSNLbar.ToString("0.000###")); else if( emaDXYbar < emaDXYbar - 1 && snl.Closebar > emaSNLbar ) ExitAtMarket(bar + 1, p, "S_exit DXY"); } } } } } } }