I have two different TimeSeries, bars and pctRank, that come from different sources that need their DataTimes synchronized for a WriteToDebugLog statement in the Execute{} block. When they are correctly synchronized, the pctRanks of the second WriteToDebugLog statement should come out sorted. Right now they are scrambled. How do I fix this?
In the code below, only the WriteToDebugLog statements in the Execute block are relevant to the DateTimes sync problem. The rest of the code in only included for completeness. If you need my Local.Components.dll library to run this code, I can send it.
In the code below, only the WriteToDebugLog statements in the Execute block are relevant to the DateTimes sync problem. The rest of the code in only included for completeness. If you need my Local.Components.dll library to run this code, I can send it.
CODE:
using System; using System.Collections.Generic; using System.Drawing; using System.Text; using WealthLab.Core; using WealthLab.Backtest; using WealthLab.Indicators; using Superticker.Components; namespace WealthScript1 { public class SelSecTradeRank : UserStrategyBase { public SelSecTradeRank() { AddParameter("Gain vs dip effect", ParameterTypes.Double, 1.00, 0.8, 1.8, 0.1) .Hint="Influence of recent gain to merit ranking"; AddParameter("Dip recovery influence", ParameterTypes.Double, 0.90, 0.0, 0.9, 0.1) .Hint="Recent dip recovery boost"; AddParameter("RegEMA affect", ParameterTypes.Double, 1, 0.0, 1.25, 0.25) .Hint="EMA regularization"; SetChartDrawingOptions(WLUtil.HideVolume()); } static List<BarHistory> topBuys = new List<BarHistory>(); static List<BarHistory> topHolds = new List<BarHistory>(); StringBuilder topBuysString = new StringBuilder(160); public override void Initialize(BarHistory bars) { emaRegular = Parameters[2].AsDouble; //paramEmaRegular meritScore = new TimeSeries(bars.DateTimes); bars.Cache["MeritTS"] = meritScore; //Merit TimeSeries for sorting decorrelated = RSDif.Decorrelate(bars); bars.Cache["DecorrTS"] = decorrelated; //decorrelated TimeSeries PlotTimeSeriesLine(decorrelated, bars.Symbol + " decorrelated", "decorrelated", Color.Green, 2, LineStyles.Solid); SetPaneDrawingOptions("decorrelated", 150, -2); RegEmaFit regEmaFit = new RegEmaFit(this as UserStrategyBase, decorrelated, "decorrelated", 0.4, emaRegular, decorrelated.Count, false); PlotTimeSeriesLine(regEmaFit.YModelTS(), bars.Symbol + " regEMA", "decorrelated", Color.Red, 2, LineStyles.Dashed); pctRank = bars.Close.PercentRank(220); bars.Cache["PctRankTS"] = pctRank; StartIndex = pctRank.FirstValidIndex; PlotTimeSeriesLine(pctRank, bars.Symbol + " fractional rank", "percentRank", Color.YellowGreen, 2, LineStyles.Solid); SetPaneDrawingOptions("percentRank", 60, 1); } //called once prior to the start of each bar; determine and sort by dipBuyMeritScore public override void PreExecute(DateTime dt, List<BarHistory> participants) { double gainVsDip = Parameters[0].AsDouble; //paramGainVsDip double rcntPerfBoost = Parameters[1].AsDouble; //paramRcntPerfBoost double dipBuyMeritScore; //for each fund in DataSet, calculate dipBuyMeritScore foreach (BarHistory bars in participants) { decorrelated = (TimeSeries)bars.Cache["DecorrTS"]; int idx = GetCurrentIndex(bars); //rtn index of the BarHistory currently being processed int lowestRecentBar = decorrelated.GetLowestBar(idx, 22); //lowest bar for past month int gainBars = idx - lowestRecentBar; //#of bars to determine recent price gains (idx-1?) pctRank = (TimeSeries)bars.Cache["PctRankTS"]; dipBuyMeritScore = 1 - pctRank[idx]; meritScore = (TimeSeries)bars.Cache["MeritTS"]; meritScore[idx] = dipBuyMeritScore; bars.UserData = dipBuyMeritScore; //save merit score w/BarHistory instance } //sort highest meritScore values where participants[0] participants.Sort((b,a) => a.UserDataAsDouble.CompareTo(b.UserDataAsDouble)); topBuys.Clear(); topHolds.Clear(); int nEndTop = Math.Min(3,participants.Count); //select top 3 funds for (int n = 0; n < nEndTop; n++) { topBuys.Add(participants[n]); topHolds.Add(participants[n]); //WriteToDebugLog(string.Format("{0}=n {1:0.00}=meritScore",n,participants[n].UserDataAsDouble)); } for (int n = nEndTop; n < Math.Min(11, participants.Count); n++) //hold top 20 funds { topHolds.Add(participants[n]); //WriteToDebugLog(string.Format("{0}=n {1:0.00}=meritScore",n,participants[n].UserDataAsDouble)); } } public override void Execute(BarHistory bars, int idx) { //bool inBuyList = topBuys.Contains(bars); if (HasOpenPosition(bars, PositionType.Long)) { //sell logic, sell if stock is not in the topHolds list if (!topHolds.Contains(bars)) PlaceTrade(bars, TransactionType.Sell, OrderType.Market); } else { //buy logic - buy if stock is in the topBuys list if (topBuys.Contains(bars)) { PlaceTrade(bars, TransactionType.Buy, OrderType.Market); topBuysString.Clear(); foreach (BarHistory barsInTopList in topBuys) { topBuysString.Append(barsInTopList.Symbol + " "); } DrawHeaderText("Buy " + bars.Symbol.Substring(1,3) + (idx+1).ToString(" @bar 000: ") + topBuysString.ToString(), Color.Green, 10, "decorrelated"); topBuysString.Append("\n"); foreach (BarHistory barsInTopList in topHolds) { pctRank = (TimeSeries)barsInTopList.Cache["PctRankTS"]; WriteToDebugLog(bars.DateTimes[idx].ToShortDateString() + ", " + pctRank.DateTimes[idx].ToShortDateString()); topBuysString.Append(string.Format("{0} {1:.00}, ",barsInTopList.Symbol.Substring(1,3),pctRank[idx])); } WriteToDebugLog("Buy " + bars.Symbol.Substring(1,3) + (idx+1).ToString(" @bar 000: ") + topBuysString.ToString()); } } } public override void Cleanup(BarHistory bars) { meritScore = (TimeSeries)bars.Cache["MeritTS"]; PlotTimeSeries(meritScore, bars.Symbol + " merit scores", "meritScores", Color.DarkRed, PlotStyles.Dots); SetPaneDrawingOptions("meritScores", 60, -1); } //shared strategy variables double emaRegular; TimeSeries meritScore,decorrelated,pctRank; } }
Rename
CODE:
// IS: pctRank = (TimeSeries)barsInTopList.Cache["PctRankTS"]; // TRY THIS: pctRank = TimeSeriesSynchronizer.Synchronize((TimeSeries)barsInTopList.Cache["PctRankTS"], bars.Close);
That modification fixed the pctRank issue okay. Thanks a bunch! See fixed code below.
But the list of pctRank over the different funds (In the Execute WriteToDebugLog) remains scrambled when they should be sorted by design. See screenshot below. How can that be fixed?
Here's the new Execute code with the DateTime synchronization fix.
But the list of pctRank over the different funds (In the Execute WriteToDebugLog) remains scrambled when they should be sorted by design. See screenshot below. How can that be fixed?
Here's the new Execute code with the DateTime synchronization fix.
CODE:Perhaps calling the Synchronizer within a ForEach loop isn't the best solution for efficiency if only one value is going to be used out of each pctRank TimeSeries. I appreciate that thought. But I'm just trying to get this to run for now. I'll go back and fix the efficiency issues later.
public override void Execute(BarHistory bars, int idx) { //bool inBuyList = topBuys.Contains(bars); if (HasOpenPosition(bars, PositionType.Long)) { //sell logic, sell if stock is not in the topHolds list if (!topHolds.Contains(bars)) PlaceTrade(bars, TransactionType.Sell, OrderType.Market); } else { //buy logic - buy if stock is in the topBuys list if (topBuys.Contains(bars)) { PlaceTrade(bars, TransactionType.Buy, OrderType.Market); topBuysString.Clear(); foreach (BarHistory barsInTopList in topBuys) { topBuysString.Append(barsInTopList.Symbol + " "); } DrawHeaderText("Buy " + bars.Symbol.Substring(1,3) + (idx+1).ToString(" @bar 000: ") + topBuysString.ToString(), Color.Green, 10, "decorrelated"); topBuysString.Append("\n"); foreach (BarHistory barsInTopList in topHolds) { pctRank = TimeSeriesSynchronizer.Synchronize((TimeSeries)barsInTopList.Cache["PctRankTS"],bars); //pctRank = (TimeSeries)barsInTopList.Cache["PctRankTS"]; WriteToDebugLog(bars.DateTimes[idx].ToShortDateString() + ", " + pctRank.DateTimes[idx].ToShortDateString()); topBuysString.Append(string.Format("{0} {1:.00}, ",barsInTopList.Symbol.Substring(1,3),pctRank[idx])); } WriteToDebugLog("Buy " + bars.Symbol.Substring(1,3) + (idx+1).ToString(" @bar 000: ") + topBuysString.ToString()); } } }
I’m not at the computer at the moment, but a quick look at the circled numbers had me thinking that they appear sorted by numeric value to me. How did you want them to be sorted?
QUOTE:Interesting. You're right! I just paged through 20 of the funds in the DebugLog to verify that.
a quick look at the circled numbers had me thinking that they appear sorted by numeric value to me.
But they are sorted in inverted order from how they appear in the PreExecute sort.
UPDATE: I screwed up. The pctRank is flipped around from the meritScore (for buying the funds). That's why things look inverted. It's working as coded now. No problems I "think".
I was able the rewrite the Execute block to replace "pctRank" with "meritScoreUnsync" and get rid of the Synchronize line for efficiency below. It is running "as designed". I only wish it made better money, but that's another problem.
CODE:
public override void Execute(BarHistory bars, int idx) { if (HasOpenPosition(bars, PositionType.Long)) { //sell logic, sell if stock is not in the topHolds list if (!topHolds.Contains(bars)) PlaceTrade(bars, TransactionType.Sell, OrderType.Market); } else { //buy logic - buy if stock is in the topBuys list if (topBuys.Contains(bars)) { PlaceTrade(bars, TransactionType.Buy, OrderType.Market); topBuysString.Clear(); foreach (BarHistory barsInTopList in topBuys) { topBuysString.Append(barsInTopList.Symbol + " "); } DrawHeaderText("Buy " + bars.Symbol.Substring(1,3) + (idx+1).ToString(" @bar 000: ") + topBuysString.ToString(), Color.Green, 10, "decorrelated"); topBuysString.Append("\n"); DateTime currentDate = bars.DateTimes[idx]; foreach (BarHistory barsInTopList in topHolds) { //meritScore = TimeSeriesSynchronizer.Synchronize((TimeSeries)barsInTopList.Cache["MeritTS"],bars); TimeSeries meritScoreUnsync = (TimeSeries)barsInTopList.Cache["MeritTS"]; //topBuysString.Append(string.Format("{0} {1:.00}, ",barsInTopList.Symbol.Substring(1,3),meritScore[idx])); topBuysString.Append(string.Format("{0} {1:.00}, ",barsInTopList.Symbol.Substring(1,3),meritScoreUnsync[meritScoreUnsync.IndexOf(currentDate)])); } WriteToDebugLog("Buy " + bars.Symbol.Substring(1,3) + (idx+1).ToString(" @bar 000: ") + topBuysString.ToString()); } } }
Your Response
Post
Edit Post
Login is required