- ago
Just wanted to share this code of a seasonal trading system which does some nice plotting with ScottPlot:



CODE:
using WealthLab.Backtest; using System; using WealthLab.Core; using System.Drawing; using System.Collections.Generic; using System.Linq; using ScottPlot; using System.Globalization; namespace WealthScript1 {    public class MonthData    {       public MonthData() { }       public MonthData(int month, int year, double avgPrice)       {          Month = month; Year = year; AvgPrice = avgPrice;       }       public int Month;       public int Year;       public double AvgPrice;    }    public class SC_2019_09_KaufmanSeasonality : UserStrategyBase    {       int paramYears, howManyYearsToAverage, firstYearWithValidData, startBar, paramThresholdHigh, paramThresholdLow;       double thresholdHigh, thresholdLow;       Dictionary<double, double> lstFreqUp = new Dictionary<double, double>();       Dictionary<int, Tuple<double, double>> lstBreakdown = new Dictionary<int, Tuple<double, double>>();       public SC_2019_09_KaufmanSeasonality()       {          AddParameter("Average, Years", ParameterTypes.Int32, 4, 2, 100, 1);          AddParameter("Use (H+L)/2 or Close", ParameterTypes.Int32, 0, 0, 1, 1);          AddParameter("High freq >", ParameterTypes.Int32, 75, 50, 90, 5);          AddParameter("Low freq <", ParameterTypes.Int32, 25, 5, 50, 5);       }       //create indicators and other objects here, this is executed prior to the main trading loop       public override void Initialize(BarHistory bars)       {          if (bars.Scale != HistoryScale.Monthly)          {             DrawHeaderText("Please switch to Monthly scale");             return;          }          #region   Declarations          howManyYearsToAverage = Parameters[0].AsInt;          firstYearWithValidData = bars.DateTimes[0].Year + howManyYearsToAverage;          startBar = bars.IndexOf(new DateTime(firstYearWithValidData, 12, 31), false);          StartIndex = startBar;          int paramPrice = Parameters[1].AsInt;          //3. Only trade if the high frequency is 75 % or greater and the low frequency is 25 % or lower.          paramThresholdHigh = Parameters[2].AsInt;          paramThresholdLow = Parameters[3].AsInt;          thresholdHigh = paramThresholdHigh / 100d;          thresholdLow = paramThresholdLow / 100d;          #endregion   Declarations                   #region   Series          //Average annual price          TimeSeries avgYearlyPrice = TimeSeriesCompressor.ToYearly(bars.AveragePriceHL);          //Average monthly prices (take AveragePrice or simply Close)          TimeSeries avgMonthlyPrice = paramPrice == 0 ? bars.AveragePriceHL : bars.Close;          avgMonthlyPrice = TimeSeriesCompressor.ToMonthly(avgMonthlyPrice);          avgMonthlyPrice = TimeSeriesSynchronizer.Synchronize(avgMonthlyPrice, bars);          avgYearlyPrice = TimeSeriesSynchronizer.Synchronize(avgYearlyPrice, bars);          PlotTimeSeriesLine(avgMonthlyPrice, "Avg Monthly Price", "avg", Color.DarkBlue, 2);          PlotTimeSeriesLine(avgYearlyPrice, "Avg Yearly Price", "avg", Color.DarkRed, 2);          #endregion          #region Collect monthly average price          var lstMonths = new List<MonthData>();          for (int bar = 1; bar < bars.Count; bar++)          {             if (bars.DateTimes[bar].Month != bars.DateTimes[bar - 1].Month) //New month             {                lstMonths.Add(new MonthData(bars.DateTimes[bar].Month, bars.DateTimes[bar].Year, avgMonthlyPrice[bar]));             }          }          #endregion          for (int bar = startBar; bar < bars.Count; bar++)          {             if (bar <= 0)                continue;             int yearTo = bars.DateTimes[bar].Year;             int yearFrom = yearTo - 1 - howManyYearsToAverage;             //Average price by year             var yearlyAverages = lstMonths.GroupBy(i => i.Year)                .Where(i => i.Key < yearTo & i.Key >= yearFrom)                .Select(g => new { Year = g.Key, Average = g.Average(a => a.AvgPrice) });             //Calculate Monthly Adjusted Returns, Up Months and Frequency of Positive Returns             for (int month = 1; month <= 12; month++)             {                int monthCount = 0, upMonths = 0;                double freqUp = 0d, monthlyAdjReturn = 0d;                foreach (var m in lstMonths)                {                   //Ensure this year's data is excluded from processing/trading                   if (m.Month == month && m.Year < yearTo && m.Year >= yearFrom)                   {                      monthCount++;                      var givenYearAverage = yearlyAverages.GroupBy(i => i.Year).                         Where(i => i.Key == m.Year).First().ToList();                      var adjReturn = m.AvgPrice / givenYearAverage[0].Average - 1;                      if (adjReturn > 0)                         upMonths++;                      monthlyAdjReturn += adjReturn;                   }                }                if (monthCount > 0)                {                   freqUp = upMonths / (double)monthCount;                   monthlyAdjReturn /= monthCount;                }                //1. Average the monthly frequency of the past N years.                if (!lstFreqUp.ContainsKey(month))                   lstFreqUp.Add(month, freqUp * 100);                if (!lstBreakdown.ContainsKey(month))                   lstBreakdown.Add(month, new Tuple<double, double>(freqUp, monthlyAdjReturn));             }          }          //Plot actual chart of Frequency of Positive Returns (for last N years)          Bitmap bmp = null;          Plot plt = new ScottPlot.Plot(600, 400);          plt.Title(string.Format("A Simple Way To Trade Seasonality of {0}", bars.Symbol));          plt.YLabel("Frequency of Positive Returns");          plt.XLabel("Month");          // make the bar plot          plt.PlotBar(lstFreqUp.Keys.ToArray(), lstFreqUp.Values.ToArray(), showValues: true);          // customize the plot to make it look nicer          plt.Grid(enable: false, lineStyle: LineStyle.Dot);          // apply custom axis tick labels          string[] lstTicks = new string[13]{"","Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"};          plt.XTicks(lstTicks);                    bmp = plt.GetBitmap();          DrawImage(bmp, bars.Count - 50, bars.Close[bars.Count - 10], "Price");       }       //execute the strategy rules here, this is executed once for each bar in the backtest history       public override void Execute(BarHistory bars, int idx)       {          if (!HasOpenPosition(bars, PositionType.Long))          {             //code your buy conditions here             //Month numbers with frequency higher (lower) than a threshold             var highFreqMonths = lstFreqUp.Where(p => p.Value > thresholdHigh);             var lowFreqMonths = lstFreqUp.Where(p => p.Value < thresholdLow);             var resultsAreValid = (highFreqMonths.Count() > 0 && lowFreqMonths.Count() > 0);             if (resultsAreValid)             {                //2. Find the last occurrences of the highest (lowest) frequency                int lastHighestFrequencyMonth = 0, lastLowestFrequencyMonth = 0;                lastHighestFrequencyMonth = (int)highFreqMonths.LastOrDefault().Key;                lastLowestFrequencyMonth = (int)lowFreqMonths.LastOrDefault().Key;                //4.If the high frequency comes first, sell short at the end of the month with the high frequency.                if (lastHighestFrequencyMonth < lastLowestFrequencyMonth)                {                   if (bars.DateTimes[idx].Month == lastHighestFrequencyMonth)                   {                      Transaction t = PlaceTrade(bars, TransactionType.Short, OrderType.MarketClose, 0, lastHighestFrequencyMonth.ToString());                      //Cover the short at the end of the month with the low frequency.                      t.Tag = (object)lastHighestFrequencyMonth;                   }                }                //5. If the low frequency comes first, buy at the end of the month with the low frequency.                else                {                   if (bars.DateTimes[idx].Month == lastLowestFrequencyMonth)                   {                      Transaction t = PlaceTrade(bars, TransactionType.Buy, OrderType.MarketClose, 0, lastLowestFrequencyMonth.ToString());                      //Sell to exit at the end of the month with the high frequency.                      t.Tag = (object)lastHighestFrequencyMonth;                   }                }             }          }          else          {             //code your sell conditions here             int monthToExit = (int)LastPosition.Tag;             if (bars.DateTimes[idx].Month == monthToExit)                ClosePosition(LastPosition, OrderType.MarketClose, 0, monthToExit.ToString());          }       }       //declare private variables below    } }
3
428
3 Answers

Reply

Bookmark

Sort
- ago
#1
Hi,

I am trying to adapt this script for WL8, but am having some issues and I am afraid that sorting out the errors that I am getting is beyond my current C# skills.

Any chance of posting the code for WL8, please?

Thank you!
0
- ago
#2
Here you go ...

CODE:
using WealthLab.Backtest; using System; using WealthLab.Core; using System.Drawing; using System.Collections.Generic; using System.Linq; using ScottPlot; using System.Globalization; namespace WealthScript1 {    public class MonthData    {       public MonthData() { }       public MonthData(int month, int year, double avgPrice)       {          Month = month; Year = year; AvgPrice = avgPrice;       }       public int Month;       public int Year;       public double AvgPrice;    }    public class SC_2019_09_KaufmanSeasonality : UserStrategyBase    {       int paramYears, howManyYearsToAverage, firstYearWithValidData, startBar, paramThresholdHigh, paramThresholdLow;       double thresholdHigh, thresholdLow;       Dictionary<double, double> lstFreqUp = new Dictionary<double, double>();       Dictionary<int, Tuple<double, double>> lstBreakdown = new Dictionary<int, Tuple<double, double>>();       public SC_2019_09_KaufmanSeasonality()       {          AddParameter("Average, Years", ParameterType.Int32, 4, 2, 100, 1);          AddParameter("Use (H+L)/2 or Close", ParameterType.Int32, 0, 0, 1, 1);          AddParameter("High freq >", ParameterType.Int32, 75, 50, 90, 5);          AddParameter("Low freq <", ParameterType.Int32, 25, 5, 50, 5);       }       //create indicators and other objects here, this is executed prior to the main trading loop       public override void Initialize(BarHistory bars)       {          if (bars.Scale != HistoryScale.Monthly)          {             DrawHeaderText("Please switch to Monthly scale");             return;          }          #region Declarations          howManyYearsToAverage = Parameters[0].AsInt;          firstYearWithValidData = bars.DateTimes[0].Year + howManyYearsToAverage;          startBar = bars.IndexOf(new DateTime(firstYearWithValidData, 12, 31), false);          StartIndex = startBar;          int paramPrice = Parameters[1].AsInt;          //3. Only trade if the high frequency is 75 % or greater and the low frequency is 25 % or lower.          paramThresholdHigh = Parameters[2].AsInt;          paramThresholdLow = Parameters[3].AsInt;          thresholdHigh = paramThresholdHigh / 100d;          thresholdLow = paramThresholdLow / 100d;          #endregion Declarations          #region Series          //Average annual price          TimeSeries avgYearlyPrice = TimeSeriesCompressor.ToYearly(bars.AveragePriceHL);          //Average monthly prices (take AveragePrice or simply Close)          TimeSeries avgMonthlyPrice = paramPrice == 0 ? bars.AveragePriceHL : bars.Close;          avgMonthlyPrice = TimeSeriesCompressor.ToMonthly(avgMonthlyPrice);          avgMonthlyPrice = TimeSeriesSynchronizer.Synchronize(avgMonthlyPrice, bars);          avgYearlyPrice = TimeSeriesSynchronizer.Synchronize(avgYearlyPrice, bars);          PlotTimeSeriesLine(avgMonthlyPrice, "Avg Monthly Price", "avg", WLColor.DarkBlue, 2);          PlotTimeSeriesLine(avgYearlyPrice, "Avg Yearly Price", "avg", WLColor.DarkRed, 2);          #endregion          #region Collect monthly average price          var lstMonths = new List<MonthData>();          for (int bar = 1; bar < bars.Count; bar++)          {             if (bars.DateTimes[bar].Month != bars.DateTimes[bar - 1].Month) //New month             {                lstMonths.Add(new MonthData(bars.DateTimes[bar].Month, bars.DateTimes[bar].Year, avgMonthlyPrice[bar]));             }          }          #endregion          for (int bar = startBar; bar < bars.Count; bar++)          {             if (bar <= 0)                continue;             int yearTo = bars.DateTimes[bar].Year;             int yearFrom = yearTo - 1 - howManyYearsToAverage;             //Average price by year             var yearlyAverages = lstMonths.GroupBy(i => i.Year)              .Where(i => i.Key < yearTo & i.Key >= yearFrom)              .Select(g => new { Year = g.Key, Average = g.Average(a => a.AvgPrice) });             //Calculate Monthly Adjusted Returns, Up Months and Frequency of Positive Returns             for (int month = 1; month <= 12; month++)             {                int monthCount = 0, upMonths = 0;                double freqUp = 0d, monthlyAdjReturn = 0d;                foreach (var m in lstMonths)                {                   //Ensure this year's data is excluded from processing/trading                   if (m.Month == month && m.Year < yearTo && m.Year >= yearFrom)                   {                      monthCount++;                      var givenYearAverage = yearlyAverages.GroupBy(i => i.Year).                       Where(i => i.Key == m.Year).First().ToList();                      var adjReturn = m.AvgPrice / givenYearAverage[0].Average - 1;                      if (adjReturn > 0)                         upMonths++;                      monthlyAdjReturn += adjReturn;                   }                }                if (monthCount > 0)                {                   freqUp = upMonths / (double)monthCount;                   monthlyAdjReturn /= monthCount;                }                //1. Average the monthly frequency of the past N years.                if (!lstFreqUp.ContainsKey(month))                   lstFreqUp.Add(month, freqUp * 100);                if (!lstBreakdown.ContainsKey(month))                   lstBreakdown.Add(month, new Tuple<double, double>(freqUp, monthlyAdjReturn));             }          }          //Plot actual chart of Frequency of Positive Returns (for last N years)          Bitmap bmp = null;          Plot plt = new ScottPlot.Plot(600, 400);          plt.Title(string.Format("A Simple Way To Trade Seasonality of {0}", bars.Symbol));          plt.YLabel("Frequency of Positive Returns");          plt.XLabel("Month");          // make the bar plot          plt.PlotBar(lstFreqUp.Keys.ToArray(), lstFreqUp.Values.ToArray(), showValues: true);          // customize the plot to make it look nicer          plt.Grid(enable: false, lineStyle: ScottPlot.LineStyle.Dot);          // apply custom axis tick labels          string[] lstTicks = new string[13] { "", "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };          plt.XTicks(lstTicks);          bmp = plt.GetBitmap();          DrawImage(bmp, bars.Count - 50, bars.Close[bars.Count - 10], "Price");       }       //execute the strategy rules here, this is executed once for each bar in the backtest history       public override void Execute(BarHistory bars, int idx)       {          if (!HasOpenPosition(bars, PositionType.Long))          {             //code your buy conditions here             //Month numbers with frequency higher (lower) than a threshold             var highFreqMonths = lstFreqUp.Where(p => p.Value > thresholdHigh);             var lowFreqMonths = lstFreqUp.Where(p => p.Value < thresholdLow);             var resultsAreValid = (highFreqMonths.Count() > 0 && lowFreqMonths.Count() > 0);             if (resultsAreValid)             {                //2. Find the last occurrences of the highest (lowest) frequency                int lastHighestFrequencyMonth = 0, lastLowestFrequencyMonth = 0;                lastHighestFrequencyMonth = (int)highFreqMonths.LastOrDefault().Key;                lastLowestFrequencyMonth = (int)lowFreqMonths.LastOrDefault().Key;                //4.If the high frequency comes first, sell short at the end of the month with the high frequency.                if (lastHighestFrequencyMonth < lastLowestFrequencyMonth)                {                   if (bars.DateTimes[idx].Month == lastHighestFrequencyMonth)                   {                      Transaction t = PlaceTrade(bars, TransactionType.Short, OrderType.MarketClose, 0, lastHighestFrequencyMonth.ToString());                      //Cover the short at the end of the month with the low frequency.                      t.Tag = (object)lastHighestFrequencyMonth;                   }                }                //5. If the low frequency comes first, buy at the end of the month with the low frequency.                else                {                   if (bars.DateTimes[idx].Month == lastLowestFrequencyMonth)                   {                      Transaction t = PlaceTrade(bars, TransactionType.Buy, OrderType.MarketClose, 0, lastLowestFrequencyMonth.ToString());                      //Sell to exit at the end of the month with the high frequency.                      t.Tag = (object)lastHighestFrequencyMonth;                   }                }             }          }          else          {             //code your sell conditions here             int monthToExit = (int)LastPosition.Tag;             if (bars.DateTimes[idx].Month == monthToExit)                ClosePosition(LastPosition, OrderType.MarketClose, 0, monthToExit.ToString());          }       }       //declare private variables below    } }
1
- ago
#3
Thank you very much!
0

Reply

Bookmark

Sort