Here is the C# Code for the Correspinding Trading War Room Youtube video just published!
Link to Video:
https://youtu.be/uKu3I04mwZ0
Link to Video:
https://youtu.be/uKu3I04mwZ0
CODE:
using WealthLab.Backtest; using System; using WealthLab.Core; using System.Drawing; using System.Collections.Generic; using System.Linq; namespace WealthScript1 { public class MyStrategy : UserStrategyBase { //Initialize - create Returns Trackers to log percentage returns after certain intervals public override void Initialize(BarHistory bars) { for (int mState = 0; mState < 4; mState++) { _returnTrackers[mState] = new List<ReturnsTracker>(); foreach (int period in _nBarPeriods) { ReturnsTracker rt = new ReturnsTracker(bars, period); _returnTrackers[mState].Add(rt); } } } //Execute public override void Execute(BarHistory bars, int idx) { //track high, low closes, pullbacks double c = bars.Close[idx]; if (c > _highestClose) _highestClose = c; if (c < _lowestClose) _lowestClose = c; double bullPullback = (_highestClose - c) * 100.0 / _highestClose; double bearPullback = (c - _lowestClose) * 100.0 / _lowestClose; //make calculates and counts based on current market state switch (_marketState) { case MarketState.Undefined: if (bullPullback >= 20.0) BeginBearMarket(idx, c); else if (bearPullback >= 20.0) BeginBullMarket(idx, c); break; case MarketState.Bull: case MarketState.BullCorrection: if (bullPullback >= 20.0) BeginBearMarket(idx, c); else if (bullPullback >= 10.0) { if (_marketState == MarketState.Bull) _bullCorrs++; _marketState = MarketState.BullCorrection; } else _marketState = MarketState.Bull; break; case MarketState.Bear: case MarketState.BearCorrection: if (bearPullback >= 20.0) BeginBullMarket(idx, c); else if (bearPullback >= 10.0) { if (_marketState == MarketState.Bear) _bearCorrs++; _marketState = MarketState.BearCorrection; } else _marketState = MarketState.Bear; break; } //color chart based on market state Color color = Color.Transparent; switch (_marketState) { case MarketState.BullCorrection: color = Color.FromArgb(32, 128, 255, 128); break; case MarketState.Bull: color = Color.FromArgb(64, 0, 255, 0); break; case MarketState.BearCorrection: color = Color.FromArgb(32, 255, 128, 128); break; case MarketState.Bear: color = Color.FromArgb(64, 255, 0, 0); break; } SetBackgroundColor(bars, idx, color); //Log N-Bar returns for the current state if (_marketState != MarketState.Undefined) { int mState = (int)_marketState; List<ReturnsTracker> lst = _returnTrackers[mState]; foreach(ReturnsTracker rt in lst) rt.CalcReturns(idx); } } //output public override void Cleanup(BarHistory bars) { //record length of current state if (_startIdx > -1) { int length = bars.Count - 1 - _startIdx; if (_marketState == MarketState.Bull || _marketState == MarketState.BullCorrection) _bullLengths.Add(length); else _bearLengths.Add(length); } //show current state on chart DrawHeaderText("Market State is: " + _marketState, Color.Black, 12); //debug log WriteToDebugLog("Bull Markets: " + _bulls); if (_bullLengths.Count > 0) WriteToDebugLog("Average Length: " + _bullLengths.Average().ToString("N2")); WriteToDebugLog("Corrections: " + _bullCorrs); if (_bullCorrs > 0) WriteToDebugLog("Chance of Correction -> Bear Market: " + (_bears * 100.0 / _bullCorrs).ToString("N2") + "%"); WriteToDebugLog(""); WriteToDebugLog("Bear Markets: " + _bears); if (_bearLengths.Count > 0) WriteToDebugLog("Average Length: " + _bearLengths.Average().ToString("N2")); WriteToDebugLog("Corrections: " + _bearCorrs); if (_bullCorrs > 0) WriteToDebugLog("Chance of Correction -> Bull Market: " + (_bulls * 100.0 / _bearCorrs).ToString("N2") + "%"); //report N-Bar Returns for each State WriteToDebugLog(""); WriteToDebugLog("N-Bar Returns by Market State"); string header = "\t\t\tday\tweek\tmnth\t3m\t6m\t1y"; WriteToDebugLog(header); for (int mState = 0; mState < 4; mState++) { MarketState ms = (MarketState)mState; string line = ms.ToString(); if (line.Length == 4) line += " "; line += "\t"; List<ReturnsTracker> lst = _returnTrackers[mState]; foreach(ReturnsTracker rt in lst) line += rt.AvgReturn.ToString("N2") + "\t"; WriteToDebugLog(line); } } //private members private MarketState _marketState = MarketState.Undefined; private double _highestClose = Double.MinValue; private double _lowestClose = Double.MaxValue; private int _bears, _bulls = 0; private int _bearCorrs, _bullCorrs = 0; private int _startIdx = -1; private List<int> _bullLengths = new List<int>(); private List<int> _bearLengths = new List<int>(); private List<ReturnsTracker>[] _returnTrackers = new List<ReturnsTracker>[4]; private List<int> _nBarPeriods = new List<int> { 1, 5, 252 / 12, 252 / 4, 252 / 2, 252 }; //begin a bull market private void BeginBullMarket(int idx, double price) { _marketState = MarketState.Bull; _highestClose = price; _bulls++; if (_startIdx > -1) { int length = idx - _startIdx; _bearLengths.Add(length); } _startIdx = idx; } //begin a bear market private void BeginBearMarket(int idx, double price) { _marketState = MarketState.Bear; _lowestClose = price; _bears++; if (_startIdx > -1) { int length = idx - _startIdx; _bullLengths.Add(length); } _startIdx = idx; } } //an enum to track market state public enum MarketState { Bull, BullCorrection, Bear, BearCorrection, Undefined }; //This class is used to track market returns after N-Bars public class ReturnsTracker { //constructor public ReturnsTracker(BarHistory bars, int numBars) { _bars = bars; NBars = numBars; } //Number of bars public int NBars { get; set; } //Observations public double Observations { get; set; } = 0.0; //Sum Returns public double SumReturns { get; set; } = 0.0; //Avg Return public double AvgReturn => Observations == 0 ? 0.0 : SumReturns / Observations; //log the returns public void CalcReturns(int idx) { int endIdx = idx + NBars; if (endIdx < _bars.Count) { double gain = _bars.Close[endIdx] - _bars.Close[idx]; gain = gain * 100.0 / _bars.Close[idx]; Observations++; SumReturns += gain; } } //private members private BarHistory _bars; } }
Rename
I just updated the code above with the inclusion of an average N-Bar returns tracking mechanism. It's interesting to see the average returns over different periods for each of the 4 defined market states, and the ability to run this on any index (or any asset) is very nice!
Watch for a new video describing these changes soon. A next step I might take is trying to identity profitable intraday strategies for each of the larger market states - stay tuned!
Here's my output for the Nasdaq Composite, for example:
Watch for a new video describing these changes soon. A next step I might take is trying to identity profitable intraday strategies for each of the larger market states - stay tuned!
Here's my output for the Nasdaq Composite, for example:
CODE:
---Symbol by Symbol Debug Logs--- ---$COMP--- Bull Markets: 18 Average Length: 596.44 Corrections: 133 Chance of Correction -> Bear Market: 12.78% Bear Markets: 17 Average Length: 109.71 Corrections: 60 Chance of Correction -> Bull Market: 30.00% N-Bar Returns by Market State day week mnth 3m 6m 1y Bull 0.06 0.29 1.09 3.00 6.26 12.67 BullCorrection -0.00 0.10 1.10 4.94 8.80 12.65 Bear -0.02 -0.11 0.19 1.03 2.42 12.60 BearCorrection 0.08 0.40 1.02 4.61 8.69 18.08
This is an awesome indicator. Can you please create an indicator that we can use in our strategy, such as market state indicator or bullmarket , bear market etc.
Yes, was already considering that! It’s funny, but so far I haven’t seen an indicator like this that just uses the classic definition to establish the market state.
Okay, I'm using ^IXIC (for the NASDAQ composite) over 800 bars. What adjustments do I need to do to get your numbers?
CODE:
---Symbol by Symbol Debug Logs--- ---^IXIC--- Bull Markets: 2 Average Length: 358.50 Corrections: 9 Chance of Correction -> Bear Market: 11.11% Bear Markets: 1 Average Length: 22.00 Corrections: 3 Chance of Correction -> Bull Market: 66.67% N-Bar Returns by Market State day week mnth 3m 6m 1y Bull 0.07 0.44 1.88 5.85 13.31 32.55 BullCorrection -0.04 -2.19 -0.54 15.75 29.58 48.17 Bear 1.51 3.99 17.58 37.00 51.23 83.69 BearCorrection -0.21 3.79 12.90 29.66 41.29 71.15
Looks like you need a larger data range.
Second part of the video featuring this Strategy has just been pushed ...
https://youtu.be/iGojKvwOoDw
https://youtu.be/iGojKvwOoDw
Thanks for that video. Very interesting conclusions from that summary table.
I did rework the formatting for that summary table so the decimals would line up.
I did rework the formatting for that summary table so the decimals would line up.
CODE:
//report N-Bar Returns for each State WriteToDebugLog("\nN-Bar Returns by Market State"); WriteToDebugLog("\t\t\tday\tweek\tmnth\t3mo\t6mo\t1yr"); for (int mState = 0; mState < 4; mState++) { MarketState ms = (MarketState)mState; string line = String.Format("{0,17}",ms); List<ReturnsTracker> lst = _returnTrackers[mState]; foreach(ReturnsTracker rt in lst) line += String.Format("{0,7:N2}",rt.AvgReturn); WriteToDebugLog(line); }
Here is a revamp of the code so that it works in WealthLab 8. I also implemented superticker's reworked format for the summary table:
CODE:
using WealthLab.Backtest; using System; using WealthLab.Core; using System.Drawing; using System.Collections.Generic; using System.Linq; namespace WealthScript1 { public class MyStrategy : UserStrategyBase { //Initialize - create Returns Trackers to log percentage returns after certain intervals public override void Initialize(BarHistory bars) { for (int mState = 0; mState < 4; mState++) { _returnTrackers[mState] = new List<ReturnsTracker>(); foreach (int period in _nBarPeriods) { ReturnsTracker rt = new ReturnsTracker(bars, period); _returnTrackers[mState].Add(rt); } } } //Execute public override void Execute(BarHistory bars, int idx) { //track high, low closes, pullbacks double c = bars.Close[idx]; if (c > _highestClose) _highestClose = c; if (c < _lowestClose) _lowestClose = c; double bullPullback = (_highestClose - c) * 100.0 / _highestClose; double bearPullback = (c - _lowestClose) * 100.0 / _lowestClose; //make calculates and counts based on current market state switch (_marketState) { case MarketState.Undefined: if (bullPullback >= 20.0) BeginBearMarket(idx, c); else if (bearPullback >= 20.0) BeginBullMarket(idx, c); break; case MarketState.Bull: case MarketState.BullCorrection: if (bullPullback >= 20.0) BeginBearMarket(idx, c); else if (bullPullback >= 10.0) { if (_marketState == MarketState.Bull) _bullCorrs++; _marketState = MarketState.BullCorrection; } else _marketState = MarketState.Bull; break; case MarketState.Bear: case MarketState.BearCorrection: if (bearPullback >= 20.0) BeginBullMarket(idx, c); else if (bearPullback >= 10.0) { if (_marketState == MarketState.Bear) _bearCorrs++; _marketState = MarketState.BearCorrection; } else _marketState = MarketState.Bear; break; } //color chart based on market state WLColor color = WLColor.Transparent; switch (_marketState) { case MarketState.BullCorrection: color = WLColor.FromArgb(32, 128, 255, 128); break; case MarketState.Bull: color = WLColor.FromArgb(64, 0, 255, 0); break; case MarketState.BearCorrection: color = WLColor.FromArgb(32, 255, 128, 128); break; case MarketState.Bear: color = WLColor.FromArgb(64, 255, 0, 0); break; } SetBackgroundColor(bars, idx, color); //Log N-Bar returns for the current state if (_marketState != MarketState.Undefined) { int mState = (int)_marketState; List<ReturnsTracker> lst = _returnTrackers[mState]; foreach(ReturnsTracker rt in lst) rt.CalcReturns(idx); } } //output public override void Cleanup(BarHistory bars) { //record length of current state if (_startIdx > -1) { int length = bars.Count - 1 - _startIdx; if (_marketState == MarketState.Bull || _marketState == MarketState.BullCorrection) _bullLengths.Add(length); else _bearLengths.Add(length); } //show current state on chart DrawHeaderText("Market State is: " + _marketState, WLColor.Black, 12); //debug log WriteToDebugLog("Bull Markets: " + _bulls); if (_bullLengths.Count > 0) WriteToDebugLog("Average Length: " + _bullLengths.Average().ToString("N2")); WriteToDebugLog("Corrections: " + _bullCorrs); if (_bullCorrs > 0) WriteToDebugLog("Chance of Correction -> Bear Market: " + (_bears * 100.0 / _bullCorrs).ToString("N2") + "%"); WriteToDebugLog(""); WriteToDebugLog("Bear Markets: " + _bears); if (_bearLengths.Count > 0) WriteToDebugLog("Average Length: " + _bearLengths.Average().ToString("N2")); WriteToDebugLog("Corrections: " + _bearCorrs); if (_bullCorrs > 0) WriteToDebugLog("Chance of Correction -> Bull Market: " + (_bulls * 100.0 / _bearCorrs).ToString("N2") + "%"); //report N-Bar Returns for each State WriteToDebugLog("\nN-Bar Returns by Market State"); WriteToDebugLog("\t\t\tday\tweek\tmnth\t3mo\t6mo\t1yr"); for (int mState = 0; mState < 4; mState++) { MarketState ms = (MarketState)mState; string line = String.Format("{0,17}", ms); List<ReturnsTracker> lst = _returnTrackers[mState]; foreach(ReturnsTracker rt in lst) line += String.Format("{0,7:N2}", rt.AvgReturn); WriteToDebugLog(line); } } //private members private MarketState _marketState = MarketState.Undefined; private double _highestClose = Double.MinValue; private double _lowestClose = Double.MaxValue; private int _bears, _bulls = 0; private int _bearCorrs, _bullCorrs = 0; private int _startIdx = -1; private List<int> _bullLengths = new List<int>(); private List<int> _bearLengths = new List<int>(); private List<ReturnsTracker>[] _returnTrackers = new List<ReturnsTracker>[4]; private List<int> _nBarPeriods = new List<int> { 1, 5, 252 / 12, 252 / 4, 252 / 2, 252 }; //begin a bull market private void BeginBullMarket(int idx, double price) { _marketState = MarketState.Bull; _highestClose = price; _bulls++; if (_startIdx > -1) { int length = idx - _startIdx; _bearLengths.Add(length); } _startIdx = idx; } //begin a bear market private void BeginBearMarket(int idx, double price) { _marketState = MarketState.Bear; _lowestClose = price; _bears++; if (_startIdx > -1) { int length = idx - _startIdx; _bullLengths.Add(length); } _startIdx = idx; } } //an enum to track market state public enum MarketState { Bull, BullCorrection, Bear, BearCorrection, Undefined }; //This class is used to track market returns after N-Bars public class ReturnsTracker { //constructor public ReturnsTracker(BarHistory bars, int numBars) { _bars = bars; NBars = numBars; } //Number of bars public int NBars { get; set; } //Observations public double Observations { get; set; } = 0.0; //Sum Returns public double SumReturns { get; set; } = 0.0; //Avg Return public double AvgReturn => Observations == 0 ? 0.0 : SumReturns / Observations; //log the returns public void CalcReturns(int idx) { int endIdx = idx + NBars; if (endIdx < _bars.Count) { double gain = _bars.Close[endIdx] - _bars.Close[idx]; gain = gain * 100.0 / _bars.Close[idx]; Observations++; SumReturns += gain; } } //private members private BarHistory _bars; } }
What would be really interesting is to add some columns for WL's IndexLab market sentiment oscillators such as CompMcClellen or CompTRIN. I would like to see how well these composite oscillators correlate with the BullBear results.
For market sentiment trading, I would probably use one of these composite oscillators to steer my trading. But I would like to pick the oscillator that follows the BullBear results as much as possible.
For market sentiment trading, I would probably use one of these composite oscillators to steer my trading. But I would like to pick the oscillator that follows the BullBear results as much as possible.
Why not simply use the CNN Fear & Greed data to mesure market state? I'm holding data going back to January 2011, so I could export it out of MongoDB but it would have to be maintained by the Wealth-Lab team.
Fear & Greed Data can be downloaded via https://production.dataviz.cnn.io/index/fearandgreed/graphdata. Simply feed the http-header in such a way that the endpoint believes that a real browser is coming along.
Fear & Greed Data can be downloaded via https://production.dataviz.cnn.io/index/fearandgreed/graphdata. Simply feed the http-header in such a way that the endpoint believes that a real browser is coming along.
I’ve been looking for a historical source of the Fear and Greed for ages, where did you find that link?
I’ll get this packaged as a PowerPack indicator.
It’ll be great to have, but it’s a sentiment indicator and not a replacement for the classic market state indicator which is based on price movement alone.
I’ll get this packaged as a PowerPack indicator.
It’ll be great to have, but it’s a sentiment indicator and not a replacement for the classic market state indicator which is based on price movement alone.
Let's resume this new discussion in a new topic, I'll create a CNN Fear/Greed topic.
Your Response
Post
Edit Post
Login is required