What would be the best way to implement the following rule:
a) That the given symbol is in the top 25% of [indicator value such as relative strength] for the given [dataset such as Nasdaq 100]?
a) That the given symbol is in the top 25% of [indicator value such as relative strength] for the given [dataset such as Nasdaq 100]?
Rename
1. Create a custom indicator for relative strength.
2. Rotation Strategy > choose that Indicator for Weight Factor.
Both creation and usage of custom indicators requires running WL7 with admin privileges.
2. Rotation Strategy > choose that Indicator for Weight Factor.
Both creation and usage of custom indicators requires running WL7 with admin privileges.
Here's a pattern you can use for a generic strategy. As written here, it adds 25% of total bar histories with the lowest RSI into a list called _buys. You can test if the current bar history is in the list (or not) to do some action with it.
CODE:
using WealthLab.Backtest; using System; using WealthLab.Core; using WealthLab.Indicators; using System.Drawing; using System.Collections.Generic; namespace WealthScript1 { public class IndicatorRank : UserStrategyBase { //this static list will be available in all instances of this class private static List<BarHistory> _buys = new List<BarHistory>(); private int _percentOfCandidates = 25; private int _period = 14; public IndicatorRank() { AddParameter("% of Candidates", ParameterTypes.Int32, 25, 5, 50, 5); AddParameter("Period", ParameterTypes.Int32, 14, 5, 20, 1); } public override void Initialize(BarHistory bars) { _percentOfCandidates = Parameters[0].AsInt; _period = Parameters[1].AsInt; StartIndex = _period; } public override void PreExecute(DateTime dt, List<BarHistory> participants) { if (participants.Count < 2) return; int candidates = (int)Math.Truncate(participants.Count * _percentOfCandidates / 100d); //Loop through the BarHistories of the participants, find the index that corresponds to the DateTime dt, //and save the indicator value to the bars.UserData for sorting foreach (BarHistory bars in participants) { int idx = GetCurrentIndex(bars); if (idx < _period) { bars.UserData = 1.0e10; // change this to a negative value if you change the sort from higher to lower below continue; } //create a formula and assign a value. We'll just use RSI for this example double rs = RSI.Series(bars.Close, _period)[idx]; bars.UserData = rs; } //this Sorts from lower to higher. For higher to lower, just change to .Sort(b, a) participants.Sort((a, b) => a.UserDataAsDouble.CompareTo(b.UserDataAsDouble)); //Add the participants with the highest formula score to the _buys list _buys.Clear(); _buys.AddRange(participants.GetRange(0, candidates)); } public override void Execute(BarHistory bars, int idx) { if (!HasOpenPosition(bars, PositionType.Long)) { // only buy this one if it's in the _buys list if (_buys.Contains(bars)) { PlaceTrade(bars, TransactionType.Buy, OrderType.Market); } } else { if (!_buys.Contains(bars)) PlaceTrade(bars, TransactionType.Sell, OrderType.Market); } } } }
fyi,
Made a correction above to account for participants with short histories whose indicator is not yet valid. It's this section -
Made a correction above to account for participants with short histories whose indicator is not yet valid. It's this section -
CODE:
if (idx < _period) { bars.UserData = 1.0e10; // change this to a negative value if you change the sort from higher to lower below continue; }
Thanks Cone ...
putting the indicator for ranking in the cache speeds things up ...
CODE:
using WealthLab.Backtest; using System; using WealthLab.Core; using WealthLab.Indicators; using System.Drawing; using System.Collections.Generic; namespace WealthScript1 { public class IndicatorRank : UserStrategyBase { //this static list will be available in all instances of this class private static List<BarHistory> _buys = new List<BarHistory>(); private RSI _rsi; private int _percentOfCandidates = 25; private int _period = 14; public IndicatorRank() { AddParameter("% of Candidates", ParameterTypes.Int32, 25, 5, 50, 5); AddParameter("Period", ParameterTypes.Int32, 14, 5, 20, 1); } public override void Initialize(BarHistory bars) { _period = Parameters[1].AsInt; _percentOfCandidates = Parameters[0].AsInt; _rsi = RSI.Series(bars.Close, _period); bars.Cache[_rsi.Name] = _rsi; StartIndex = _rsi.FirstValidIndex; } public override void PreExecute(DateTime dt, List<BarHistory> participants) { if (participants.Count < 2) return; int candidates = (int)Math.Truncate(participants.Count * _percentOfCandidates / 100d); //Loop through the BarHistories of the participants, find the index that corresponds to the DateTime dt, //and save the indicator value to the bars.UserData for sorting foreach (BarHistory bars in participants) { int idx = GetCurrentIndex(bars); if (idx < _period) { bars.UserData = 1.0e10; // change this to a negative value if you change the sort from higher to lower below continue; } //create a formula and assign a value. We'll just use RSI for this example // double rs = RSI.Series(bars.Close, _period)[idx]; bars.UserData = (bars.Cache[_rsi.Name] as TimeSeries)[idx]; } //this Sorts from lower to higher. For higher to lower, just change to .Sort(b, a) participants.Sort((a, b) => a.UserDataAsDouble.CompareTo(b.UserDataAsDouble)); //Add the participants with the highest formula score to the _buys list _buys.Clear(); _buys.AddRange(participants.GetRange(0, candidates)); } public override void Execute(BarHistory bars, int idx) { if (!HasOpenPosition(bars, PositionType.Long)) { // only buy this one if it's in the _buys list if (_buys.Contains(bars)) { PlaceTrade(bars, TransactionType.Buy, OrderType.Market); } } else { if (!_buys.Contains(bars)) PlaceTrade(bars, TransactionType.Sell, OrderType.Market); } } } }
Your Response
Post
Edit Post
Login is required