- ago
Can you please help with converting following script from WL6 to WL7?

CODE:
using System; using System.Collections.Generic; using System.Text; using System.Drawing; using WealthLab; using WealthLab.Indicators; namespace WealthLab.Strategies {    public class FSF_Rotation : WealthScript, IComparer<MOMHolder>    {       StrategyParameter numberOfSymbols;       StrategyParameter SMA_Period;       StrategyParameter a1;       public FSF_Rotation()       {          numberOfSymbols = CreateParameter("n Symbols", 4, 1, 12, 1);          SMA_Period = CreateParameter("SMA Period", 12, 3, 18, 1);          a1 = CreateParameter("ProtectionFactor", 2, 0, 2, 1);       }       protected override void Execute()       {          ClearDebug();          ClearExternalSymbols();          int number = numberOfSymbols.ValueInt;          int a = a1.ValueInt;          int Period = SMA_Period.ValueInt;          int N = 12; //Numero activos sin IEF          //Execute rotation strategy          List<MOMHolder> list = new List<MOMHolder>();          for (int bar = Period; bar < Bars.Count; bar++)          {             //Identify the symbols with the highest MOM             list.Clear();             int SMApos = 0;             foreach (string symbol in DataSetSymbols)             { //CREATE A LIST MOMHolder WITH THE ETF "EX IEF"                if (symbol != "IEF")                {                   SetContext(symbol, true);                   if (Bars.FirstActualBar < bar)                   {                      MOMHolder holder = new MOMHolder();                      holder.symbol = symbol;                      holder.mom = Close[bar] / SMA.Series(Bars.Close, Period)[bar] - 1;                      if (holder.mom > 0) SMApos++;                      list.Add(holder);                      PrintDebug(Date[bar] + " " + holder.symbol + " " + (holder.mom * 100).ToString("0.00") + "%");                   }                   RestoreContext();                }             }             list.Sort(this);             list.Reverse(); // Reverse sorting order to select highest MOM symbols             double BF = 100 * (N - SMApos) / (N - a * N / 4);             BF = Math.Min(100, BF); // PERCENTAGE TO BUY THE IEF             double porcent_stocks = 100 - BF;             PrintDebug(Date[bar] + " SMApos = " + SMApos + " BF = " + BF);             PrintDebug("--------------------------------------------------");             //keep top number (1 is initial default) only             int c = list.Count;             int Top = Math.Min(SMApos, number); // MAX 6 ETFS POSITIONS "NO IEF"             double porcent_stock = porcent_stocks / Top; //PERCENTAGE TO BUY EACH ETF "NO IEF"             //Close ALL positions             for (int pos = ActivePositions.Count - 1; pos >= 0; pos--)             {                Position p = ActivePositions[pos];                SellAtMarket(bar + 1, p);             }             // DELETE THE POSITIONS NO TOP OF THE LIST             for (int i = c - 1; i >= Top; i--)                list.RemoveAt(i);             //Buy new positions             foreach (MOMHolder holder in list)             {                SetContext(holder.symbol, true);                // BUY THE ETF NO IEF IF porcent_stock>0                if ((porcent_stock > 0) && (BuyAtMarket(bar + 1) != null))                {                   LastPosition.Tag = porcent_stock;                   PrintDebug(Date[bar] + " " + holder.symbol + " porcentaje asignado = " + porcent_stock.ToString("0.00") + "%");                   PrintDebug("--------------------------------------------------");                }                RestoreContext();             }             // IF THE PERCTENAGE OF BF IS > 5% ENTER ON IEF (THE SMALLEST BOUGHT FOR IEF IS 8% -> TO a=0 y n=11             if (BF > 5)             {                SetContext("IEF", true);                if (BuyAtMarket(bar + 1) != null)                {                   LastPosition.Tag = BF;                   PrintDebug(Date[bar] + " IEF porcentaje asignado = " + BF + "%");                }                RestoreContext();             }          }       }       public int Compare(MOMHolder item1, MOMHolder item2)       {          return item1.mom.CompareTo(item2.mom);       }    }    public class MOMHolder    {       internal string symbol;       internal double mom;    } }
0
3,617
Solved
39 Replies

Reply

Bookmark

Sort
- ago
#1
WL7 has Rotation Strategy built-in as a flexible wizard tool for building strategies that rotate based on any indicator with custom rebalance schedule. I recommend that you first take a look at the Help chapter for "Rotation" and explore some sample strategies like "UltOsc" (wizard type) and "Fidelity select..." (which is code based). Then if you find that you're still unable to implement some logic using the built-in tool, tell us about your difficulty and provide the system's rules in plain English.
0
- ago
#2
It would be very nice if it was possible to open a rotational strategy like in a strategy from blocks using "Open as C# Coded Strategy".
Or to be able to insert additional blocks into the rotation strategy.
0
- ago
#3
QUOTE:
Or to be able to insert additional blocks into the rotation strategy.

Could you clarify why you think it would be nice?
0
- ago
#4
Hi Eugene.
I have opened the help request because I have not found enough examples of rotational systems in "C # Coded Strategy" format to adapt my strategies from WL6 to WL7.
Honestly, although your help is great, I miss more examples of strategies with their corresponding code, which facilitates the adaptation to go from WL6 to WL7.
The request came because after trying a thousand and one ways I was not able to get it. In WL6 I was able to successfully program my strategies given the countless existing code examples to rely on, but it is something that is missing in WL7.
Hence, I requested help, based on the adaptation of this code, to be able to continue adapting other strategies that I have.
I have been very happy with WL6 for many years and I want to remain a WL7 customer for many more years, but honestly, I am currently missing more code to lean on and so I asked for help.
0
- ago
#5
Ricardo, the countless code you're referring to has not emerged overnight - it rather was created in over a decade of WL6 existence. If we find some shortage of examples we'll add them.

Before I get to translating some code I need to understand if the built-in Rotation tool doesn't satisfy (and why exactly i.e. what you think it's missing) and also the logic.
0
- ago
#6
Hi Eugene.
This rotation strategy is not possible to do with the wizard and requires code.
The 13 ETFs in the DataSet on which the system works are: DBC EEM EWJ GLD HYG IEF IWM LQD QQQ SPY TLT VGK VNQ
Of those 13 ETFS, there is 1 ETF that the system considers protection (IEF) and the other 12 (DBC EEM EWJ GLD HYG IWM LQD QQQ SPY TLT VGK VNQ) considers them risky.
1.- On the last trading day of each month, a momentum score (MOM) is calculated for each of the 12 risk ETFs:
MOM = Close [bar] /SMA.Series (Bars.Close, Period) [bar] -1;
2.- To determine the% of the portfolio to be assigned to the protection ETF (IEF), the system calculates the number of risk ETFs where MOM> 0.
If there are 6 or fewer risk ETFs with MOM> 0, the entire portfolio is assigned to IEF; otherwise, the weight that IEF will have in the portfolio will be:
% IEF = 100 * [(12-n) / 6].
The variable "n" is the number of risk ETFs with MOM> 0
3.- If n> = 7 (or, in other words, if IEF <100%), select the 4 risk ETFs with the highest MOM value and assign 1/4 of the remaining portfolio (not assigned to IEF) to each one.

For example:
If n = 8
% IEF = 100 *[(12-8)/6] -> 66%
The rest 34% is for the 4 risky ETF with higest MOM (8,5% for each one).

Result of this month in the example:
IEF 66% of the portfolio
Risky ETF1 (for example IWM) 8,5% of the protfolio
Risky ETF2 (for example EEM) 8,5% of the protfolio
Risky ETF3 (for example DBC) 8,5% of the protfolio
Risky ETF3 (for example GLD) 8,5% of the protfolio

4.- Holds positions until the last trading day of the following month, at which time the previous calculation is made again for the new month.
0
- ago
#7
QUOTE:
Could you clarify why you think it would be nice?


Different filters could be used. For example, select for rotation only those stocks that are only in an uptrend and at the same time made a small correction, or for some other parameters. For example, do not include in the rotation stocks that are below the long moving average. Room for creativity :)

0
Glitch8
 ( 8.38% )
- ago
#8
Maybe a couple of fields where you could drop BB Conditions - one area for Inclusions and another for Exclusions.
2
- ago
#9

Hello.
I keep trying to migrate the query start strategy from WL6 to WL7 and I am currently stuck in that I cannot find the following equivalences from WL6 to WL7.

What is the equivalence of ClearDebug () in WL7?
What is the equivalence of ClearExternalSymbols () in WL7?
What is the equivalence of DataSetSymbol in WL7?
What is the equivalence of RestoreContext () in WL7?
What is the equivalence of PrintDebug in WL7?

Sorry to be tiresome, but I'm really putting all my effort into completing the migration and due to the shortage of existing example code (logical because the recent release of WL7) I feel compelled to ask.
Thanks.
0
- ago
#10
Please find your questions answered in the updated QuickRef V6:

https://wl6.wealth-lab.com/Forum/Posts/Download-Version-6-9-QuickRef-with-Version-7-Equivalents-40609
0
- ago
#11
Thanks Eugene.
I've asked why in the updated version QuickRef V6 there are no equivalences for ClearDebug or ClearExternalSymbols.
For DataSetSymbol and PrintDebug it tells me to look at “Wealth-Lab 7: UserTrategyBase> Miscellaneous, but I didn't see anything that looks like the WL6 function there.
About RestoreContext it says not to be necessary.
0
- ago
#12
There are no equivalents for ClearDebug or RestoreContext (which is N/A)
0
Cone8
 ( 26.65% )
- ago
#13
What is the equivalence of ClearDebug () in WL7?
None. You should find that the Debug Log is refreshed for each run. Notice that the debug output is now segregrated by symbol. Also, if you WriteToDebugLog in BacktestBegin/Complete or Pre/PostExecute, WL7 will _generally_ write to the "same random symbol", but you can't count on it. In this case, the order of the write may not appear intuitive.

What is the equivalence of DataSetSymbol in WL7?
BacktestData (this reference is explicit in the WL6 QuickRef - right on top)

What is the equivalence of RestoreContext () in WL7?
It's not required to SetContext to operate on other symbols, so you don't have to restore it either. For trading an external symbol, get a reference to its BarHistory using GetHistory() and pass it to PlaceTrade(). See Sample Strategies > Pairs Trading

What is the equivalence of PrintDebug in WL7?
WriteToDebugLog (this reference is explicit in the WL6 QuickRef - right on top)

What is the equivalence of ClearExternalSymbols () in WL7?
I don't think this exists and is probably unnecessary. I can't remember using it even once in any my scripts.
1
- ago
#14
Thanks to both of you for the help.
I keep fighting with the migration of the strategy
0
- ago
#15
I converted a rotation strategy from WL6 to WL7 which loops through all bars in a dataset looking for certain conditions and then creates a list of top-ranked symbols at each bar which are then traded.
Unlike WL6 where the results were identical from one run to another here in WL7 each backtest produces different results. Clearly I'm doing something wrong.
1) As I understand, there are no WL7 equivalents for SetContext and RestoreContext, right?
2) Where exactly should the dataset symbol loop be placed - inside the Initialize(BarHistory bars) area or Execute (BarHistory bars, int idx) area? Currently it's under latter.

Any other additional helpful pointers would also be appreciated.
0
- ago
#16
QUOTE:
... loops through all bars in a dataset looking for certain conditions and then creates a list of top-ranked symbols at each bar which are then traded.

Go to the example for the UserStrategyBase.PreExecute{} procedure.
https://www.wealth-lab.com/Support/ApiReference/UserStrategyBase

Inside that example, study the
CODE:
public override void PreExecute(DateTime dt, List<BarHistory> participants)
procedure. It's using RSI values as its merit metric, but you can use anything. Be prepared to do some sorting on your merit metric in this procedure. That should get you started. Have fun.

You don't necessarily have to be using a rotational strategy to employ a PreExecute{} procedure.
0
- ago
#17
Thanks, I'll take a look.
0
- ago
#18
Where exactly should the dataset symbol loop be placed - inside the Initialize(BarHistory bars) area or Execute (BarHistory bars, int idx) area? Or either?
0
Cone8
 ( 26.65% )
- ago
#19
PreExecute or PostExecute.

Isn't there a Rotation C# Code Example included in the installation? TacticalAssetRotation?
0
- ago
#20
@Sammy_G

I recently transfomed all my rotation strageties from Quantacula 219 to WL7. Here's a skeleton of how to make it fly under WL7. Use the debugging in VS 2019, this helps tremendously to understand the complete process.

CODE:
private static List<BarHistory> buys = new List<BarHistory>(); private UltimateOsc myIndicator; private bool rebalance = false; public override void Initialize(BarHistory bars) { myIndicator = new UltimateOsc(bars, 7, 14,28); bars.Cache["UltimateOsc"] = myIndicator; StartIndex = 28; } public override void PreExecute(DateTime dt, List<BarHistory> participants) { rebalance = HelperUtilities.IsFirstTradingDayOfNewMonth(dt, participants); if (!rebalance) return; foreach (BarHistory bh in participants) { UltimateOsc symbol = (UltimateOsc)bh.Cache["UltimateOsc"]; int idx = GetCurrentIndex(bh); double val = symbol[idx]; if (Double.IsNaN(val)) { val = 1000; } bh.UserData = val; } participants.Sort((a, b) => a.UserDataAsDouble.CompareTo(b.UserDataAsDouble)); buys.Clear(); for (int n = 0; n < 3; n++) { if (n >= participants.Count) { break; } buys.Add(participants[n]); } } public override void Execute(BarHistory bars, int idx) { bool inBuyList = buys.Contains(bars); if (HasOpenPosition(bars, PositionType.Long) == false) { if (inBuyList == true) { Transaction t = PlaceTrade(bars, TransactionType.Buy, OrderType.Market, 0, 0); } } else { if (inBuyList == false) { Transaction t = PlaceTrade(bars, TransactionType.Sell, OrderType.Market); } } }
1
Best Answer
- ago
#21
@Cone:
I don't see a Tactical Asset Allocation, or any other C# coded, rotation strategy in my build 7 install. Am I supposed to d/l them from somewhere?

@Springroll:
Thanks! I'll study it carefully.
0
- ago
#22
QUOTE:
I don't see a Tactical Asset Allocation, or any other C# coded, rotation strategy in my build 7 install. Am I supposed to d/l them from somewhere?

It can be found under the "Sample Strategies" folder.
0
- ago
#23
This is what I have in Sample Strategies folder:
0
- ago
#24
Are you trying to migrate all the sample codes from WL6 to WL7?
There are few samples in WL7.
0
Cone8
 ( 26.65% )
- ago
#25
QUOTE:
Are you trying to migrate all the sample codes from WL6 to WL7?
I'm not sure to whom this question is addressed, but no. There are many samples in the QuickRef too, demonstrating techniques and keywords. If there's something missing that you need help with, let us know - but please start a new topic for that.
0
- ago
#26
I don't see an answer to Sammy_G's question about where the rotational strategy code examples are. Was the answer moved to another topic?

I only see two sample strategies with the word "rotation" in them, and I don't get a "C# Code Editor" tab when I open them. Maybe that's why the symbol preceding their title in the list starts with a return circle instead of "C#"? Does that indicate it is a Building Block strategy, which I am now sensing do not have C# equivalent code exposed as a sample?
0
Glitch8
 ( 8.38% )
- ago
#27
There are 4 fundamental types of Strategies in WL7:

- Code Based (derived from UserStrategyBase)
- Building Block (under the hood these are just Code Based, the code is generated based on the Building Blocks selected.)
- Rotation (derived from StrategyBase, these don't derive from UserStrategyBase and they have no Code Based representation like the others do.)
- Meta (just a combination of one or more of the above 3.)
0
- ago
#28
Thank you @Glitch. What about the answer to Sammy_G's question regarding rotation code examples?
0
- ago
#29
Posts #20 and #22.
0
Glitch8
 ( 8.38% )
- ago
#30
I don't have an answer. The question is 7 months old and he never followed up, and I'm not sure why he didn't have the Tactical Asset Rotation Strategy in his Sample Strategies folder. I can only speculate that he might have accidentally moved or deleted it.

0
- ago
#31
@Glitch I don't have it in my Sample Strategies either. My list looks exactly like Post #23 You and @Eugene clearly believe it's there, but it's not (for Sammy_G and me, at least; and no, I didn't delete it.)

How can I get it into my samples folder?
0
- ago
#32
@Eugene wrote
QUOTE:
Posts #20 and #22.


My post above addresses #22

I didn't realize that Post #20 was "validated by WealthLab" sample code. Maybe I should have taken the hint from it being marked as Best Answer
0
- ago
#33
Quite odd. Here's the code for Tactical Rotation:
CODE:
using WealthLab.Backtest; using System; using WealthLab.Core; using WealthLab.Indicators; using System.Drawing; using System.Collections.Generic; namespace WealthScript2 { public class TacticalAssetRotation : UserStrategyBase {       //declare private variables below       private TimeSeries avgROC;       private string seriesKey = "Average ROC";              //the list of symbols that we should buy each bar       private static List<BarHistory> buys = new List<BarHistory>();       //create the weight indicator and stash it into the BarHistory object for reference in PreExecute       public override void Initialize(BarHistory bars)       {          avgROC = (ROC.Series(bars.Close, 60) + ROC.Series(bars.Close, 120) + ROC.Series(bars.Close, 200)) / 3;          bars.Cache[seriesKey] = avgROC;       }       //this is called prior to the Execute loop, determine which symbols have the lowest average ROC       public override void PreExecute(DateTime dt, List<BarHistory> participants)       {          //store the symbols' AvgROC value in their BarHistory instances          foreach (BarHistory bh in participants)          {             TimeSeries symbolRoc = (TimeSeries)bh.Cache[seriesKey];             int idx = GetCurrentIndex(bh); //this returns the index of the BarHistory for the bar currently being processed             double rocVal = symbolRoc[idx];                          //if the indicator isn't valid set a high value to avoid selection in rotation             if (idx < symbolRoc.FirstValidIndex)                rocVal = 1.0e6;             bh.UserData = rocVal; //save the current AvgROC value along with the BarHistory instance          }          //sort the participants by AvgROC value (lowest to highest)          participants.Sort((a, b) => a.UserDataAsDouble.CompareTo(b.UserDataAsDouble));          //keep the top 3 symbols          buys.Clear();          for (int n = 0; n < 3; n++)          {             if (n >= participants.Count)                break;             buys.Add(participants[n]);          }       }       //execute the strategy rules here, this is executed once for each bar in the backtest history       public override void Execute(BarHistory bars, int idx) {          bool inBuyList = buys.Contains(bars);          if (!HasOpenPosition(bars, PositionType.Long))          {             //buy logic - buy if it's in the buys list             if (inBuyList)                PlaceTrade(bars, TransactionType.Buy, OrderType.Market);          }          else          {             //sell logic, sell if it's not in the buys list             if (!inBuyList)                PlaceTrade(bars, TransactionType.Sell, OrderType.Market);          } } } }
0
Glitch8
 ( 8.38% )
- ago
#34
I just solved this mystery! It turns out that there was some incorrect changes in the saved Strategy file so I'm fixing it as we speak. Will have to rename the Strategy slightly to ensure that folks get it the next time they update WL7.
2
- ago
#35
Thanks, @Eugene. Maybe it's because I d/l 'ed V7 many months ago, and *maybe* this Sample Strategy was added later, *and* updates don't update Sample Strategies? Just a guess....
0
- ago
#36
I don't think so because I just recently did a clean install of Windows 11 on my machine, followed by a fresh installation of WL7 (with all the extensions also installed) and I am also missing that script.

In fact, from the screenshot of Glitch, I am missing the following:
- Fidelity Rotation
- High Prob ETF
- Knife Juggler Coded
- RSI Agita
- Tactical Asset Rotation
- WSJ Common Sense

Are these missing because they are private but just happen to be organised in this folder; or they suffer from a similar problem and hence not showing up?

Thank you!
0
Glitch8
 ( 8.38% )
- ago
#37
The Strategy file is currently corrupted. It will be fixed in the next release and named "Tactical Asset Rotation (Updated)."
0
- ago
#38
QUOTE:
I just solved this mystery!


Hooray for @Glitch!
0

Reply

Bookmark

Sort