I might have given a bad example in post #9, so let me try again. I am trying to avoid wash sales, so I want to know if the trade closed at loss or at profit. I only know it after trade completes and I want to incorporate "wash sale" logic into PreExecute sorting process. Right now I am defining Wash as a time Series with a default value of 1 and set it to 0 for 31 calendar days after the loss, but if there is a better way of doing so, I would appreciate any recommendations.
Rename
I'm offering the code below not as a solution in its own right, although feel free to use it as is, but to illustrate that the Position variable holds all the information you need to manage wash sales. Study the code below to learn the attributes of the Position object; that's what matters here. Then write your own implementation for the Execute{} block. Do not use merit metrics and PreExecute{} sorting for wash sale management.
The code below resides in a code library, so a UserStrategyBase (usb) instance must be passed into the library code (say with the MyStrategy constructor) prior to calling it. If you're not using a code library, then you don't need to pass that usb instance.
Remember, concentrate on just the information the Position variable holds. The rest of the code is junk unless you want to highlight the bars that denote wash sale ranges and need a wash sale count for the Data Range of your strategy. You would need to call this code in the WL Cleanup{} procedure because it assumes all Position objects are fully populated. But Execute{} also has access to Position objects from earlier bars. (Obviously, Execute won't have access to future bars, though. That would be peeking.) You would manage your wash sales solely from Execute{} using only the most recent, closed Position object. The LastPosition property should be helpful.
This code has not been tested on WL7, so it comes without warranty. It was ported from WL6.
The code below resides in a code library, so a UserStrategyBase (usb) instance must be passed into the library code (say with the MyStrategy constructor) prior to calling it. If you're not using a code library, then you don't need to pass that usb instance.
CODE:
public class WLTrading //library calls referencing WealthLab (UserStrategyBase) functions { //developed by Superticker internal UserStrategyBase usb; public WLTrading(UserStrategyBase usbRef) { usb = usbRef; //UserStrategyBase object reference } static readonly TimeSpan washSaleTimeBoundary = new TimeSpan(30, 0, 0, 0); //wash sale within 30-days of sell public int WashSales(BarHistory bars, Color washSaleShade, int shadeTransparency = 120) { //Shade all wash sale bar ranges and return the #of wash sales for the data range int washSaleCount = 0; if (usb.GetPositions().Count > 1) //flag all wash sales { List<Position> positions = usb.GetPositions(); Position posCurr, posPrev = positions[0]; for (int posIndx=1; posIndx < positions.Count; posPrev=posCurr, posIndx++) { posCurr = positions[posIndx]; if (posCurr.EntryDate - posPrev.ExitDate < washSaleTimeBoundary && //wash sales < 30 calendar days posPrev.Profit < 0.0) //previous sale lost money { washSaleCount++; usb.SetBackgroundColor(bars, posPrev.EntryBar, washSaleShade); //unprofitable buy for (int bar = posPrev.EntryBar+1; bar <= posCurr.EntryBar; bar++) usb.SetBackgroundColor(bars, bar, Color.FromArgb(shadeTransparency, washSaleShade)); if (posCurr.Profit < 0.0) //color next potential wash sale usb.SetBackgroundColor(bars, posCurr.EntryBar, washSaleShade); } } } if (usb.GetPositions().Count > 0 && System.DateTime.Today-usb.LastPosition.ExitDate < washSaleTimeBoundary //wash sales < 30 calendar days && usb.LastPosition.Profit < 0.0) //previous sale lost money { for (int bar = usb.LastPosition.ExitBar+1; bar < bars.Count; bar++) usb.SetBackgroundColor(bars, bar, Color.FromArgb(shadeTransparency, washSaleShade)); } return washSaleCount; }
Remember, concentrate on just the information the Position variable holds. The rest of the code is junk unless you want to highlight the bars that denote wash sale ranges and need a wash sale count for the Data Range of your strategy. You would need to call this code in the WL Cleanup{} procedure because it assumes all Position objects are fully populated. But Execute{} also has access to Position objects from earlier bars. (Obviously, Execute won't have access to future bars, though. That would be peeking.) You would manage your wash sales solely from Execute{} using only the most recent, closed Position object. The LastPosition property should be helpful.
This code has not been tested on WL7, so it comes without warranty. It was ported from WL6.
Thank you superticker for sharing code sample - much appreciated. I'll try to use this example for the logic I am trying to implement.
Offopic discussion moved to:
https://www.wealth-lab.com/Discussion/Sharing-code-samples-7071
https://www.wealth-lab.com/Discussion/Sharing-code-samples-7071
Can this be made into a feature request? Adding avoid 30 day rebuy (wash sale) of same stock if it had a losing position? Maybe an advanced strategy setting?
Everything has to be a feature request these days unconditionally... 😄
Look up BarsSinceLastExit in the QuickRef, there's a code sample.
Look up BarsSinceLastExit in the QuickRef, there's a code sample.
Your Response
Post
Edit Post
Login is required