Conditional Probabilities Based Intraday Only
Code snippet of S&P e-mini futures trading strategy in C# for use with Multicharts.NET
Copyright 2019, Farooq Hassan, all rights reserved.
using System; using System.Collections.Generic; using System.Drawing; using System.Linq; using System.Threading; using PowerLanguage.Function; using ATCenterProxy.interop; using PowerLanguage.Indicator; using PowerLanguage.VolumeProfile;
namespace PowerLanguage.Strategy { [IOGMode(IOGMode.Enabled)] public class _RVPIBT : SignalObject { [Input] public DirectionType Direction { get; set; }
[Input]
public OrderType Order { get; set; }
[Input]
public string TickEntryEndTime { get; set; }
[Input]
public bool TickEntry { get; set; }
[Input]
public bool TickExit { get; set; }
[Input]
public int TickTouchEntry { get; set; }
[Input]
public bool IBEntry { get; set; }
[Input]
public bool IBExit { get; set; }
[Input]
public int AtrLength { get; set; }
[Input]
public bool AtrEntry { get; set; }
[Input]
public string VolumeProfileEntryTime { get; set; }
[Input]
public bool VolumeProfileEntry { get; set; }
[Input]
public bool VolumeProfileExit { get; set; }
[Input]
public bool CloseOnEOD { get; set; }
[Input]
public bool UseExpertCommentary { get; set; }
[Input]
public string TradingStartTime { get; set; }
[Input]
public string TradingEndTime { get; set; }
[Input]
public string TradeEntryEndTime { get; set; }
public enum DirectionType
{
LongShort,
Long,
Short
}
public enum OrderType
{
Limit,
MarketThisBar
}
private class VolumeProfileValues
{
public double POC { get; set; }
public double VAL { get; set; }
public double VAH { get; set; }
public double VAR { get; set; }
}
private Dictionary<EOrderAction, IOrderMarket> _marketOrder;
private Dictionary<EOrderAction, IOrderPriced> _stopOrder;
private Dictionary<EOrderAction, IOrderPriced> _limitOrder;
private bool _isBuyEnabled, _isSellEnabled;
private double _tickSize;
private int _dailyDataStream;
private IInstrument _djtic, _daily;
private TimeSpan _tradingStartTime, _tradingEndTime, _volumeProfileEntryTime, _tradeEntryEndTime, _tickEntryEndTime;
private IDataLoaderResult _dataLoaderResult;
private bool _isSubscribed;
private int _tickOverboughtCounter, _tickOversoldCounter;
private VariableSeries<bool> _isTradingTime;
private double? _initialBalanceHigh, _initialBalanceLow;
private double? _atr, m_atr;
public double? _pt, _sl, _ptf, _slf;
private VariableObject<Int32> m_counter;
private VariableObject<Double> m_yestopen;
private VariableObject<Double> m_todaysopen;
private VariableObject<Double> m_yesthigh;
private VariableObject<Double> m_todayshigh;
private VariableObject<Double> m_yestlow;
private VariableObject<Double> m_todayslow;
private VariableObject<Double> m_yestclose;
private VolumeProfileValues[] _volumeProfile;
public _RVPIBT(object ctx) : base(ctx)
{
Direction = DirectionType.LongShort;
Order = OrderType.Limit;
TickTouchEntry = 2;
AtrLength = 10;
VolumeProfileEntryTime = "9:55";
TradingStartTime = "09:30";
TradingEndTime = "16:00";
TradeEntryEndTime = "15:40";
TickEntryEndTime = "14:00";
}
protected override void Create()
{
_marketOrder = new Dictionary<EOrderAction, IOrderMarket>(4);
_stopOrder = new Dictionary<EOrderAction, IOrderPriced>(4);
_limitOrder = new Dictionary<EOrderAction, IOrderPriced>(4);
m_counter = new VariableObject<Int32>(this);
m_yestopen = new VariableObject<Double>(this);
m_todaysopen = new VariableObject<Double>(this);
m_yesthigh = new VariableObject<Double>(this);
m_todayshigh = new VariableObject<Double>(this);
m_yestlow = new VariableObject<Double>(this);
m_todayslow = new VariableObject<Double>(this);
m_yestclose = new VariableObject<Double>(this);
foreach (var orderAction in new[] { EOrderAction.Buy, EOrderAction.Sell, EOrderAction.BuyToCover, EOrderAction.SellShort })
{
_marketOrder.Add(orderAction, OrderCreator.MarketThisBar(new SOrderParameters(Contracts.Default, orderAction)));
_stopOrder.Add(orderAction, OrderCreator.Stop(new SOrderParameters(Contracts.Default, orderAction)));
_limitOrder.Add(orderAction, OrderCreator.Limit(new SOrderParameters(Contracts.Default, orderAction)));
}
_isTradingTime = new VariableSeries<bool>(this);
}
protected override void StartCalc()
{
_isBuyEnabled = true;
_isSellEnabled = true;
if (Direction == DirectionType.Long)
_isSellEnabled = false;
if (Direction == DirectionType.Short)
_isBuyEnabled = false;
_tickSize = Bars.Info.MinMove / Bars.Info.PriceScale;
_volumeProfileEntryTime = TimeSpan.Parse(VolumeProfileEntryTime);
_tradingStartTime = TimeSpan.Parse(TradingStartTime);
_tradingEndTime = TimeSpan.Parse(TradingEndTime);
_tradeEntryEndTime = TimeSpan.Parse(TradeEntryEndTime);
_volumeProfile = new VolumeProfileValues[2];
_tickEntryEndTime = TimeSpan.Parse(TickEntryEndTime);
for (var dataStream = 1; dataStream <= MaxDataStream; dataStream++)
{
var bars = BarsOfData(dataStream);
if (bars == null || bars == Bars)
continue;
var request = bars.Request;
if (request.Symbol == "DJTIC")
{
_djtic = bars;
}
else if (request.Symbol == Bars.Request.Symbol)
{
var resolution = request.Resolution;
if (resolution.Type == EResolution.Day && resolution.Size == 1)
{
_daily = bars;
_dailyDataStream = dataStream;
}
}
}
if (_daily == null)
throw new Exception("Daily data missing");
}
protected override void CalcBar()
{
if (Bars.CurrentBar < 1)
return;
OnTick();
if (Bars.Status == EBarState.Close)
{
OnBar();
}
{
if (Bars.Time[0].Date != Bars.Time[1].Date)
{
m_counter.Value = (m_counter.Value + 1);
m_yestopen.Value = m_todaysopen.Value;
m_yesthigh.Value = m_todayshigh.Value;
m_yestlow.Value = m_todayslow.Value;
m_yestclose.Value = Bars.Close[1];
m_todaysopen.Value = Bars.Open[0];
m_todayshigh.Value = Bars.High[0];
m_todayslow.Value = Bars.Low[0];
}
else{
if (PublicFunctions.DoubleGreater(Bars.High[0], m_todayshigh.Value)){
m_todayshigh.Value = Bars.High[0];
}
if (PublicFunctions.DoubleLess(Bars.Low[0], m_todayslow.Value)){
m_todayslow.Value = Bars.Low[0];
}
}
}
}
private string ToString(double? val)
{
return val.HasValue ? val.Value.ToString() : "N/A";
}
private VolumeProfileValues GetVolumeProfileValues(int barIndex)
{
var volumeProfile = VolumeProfile.ItemForBar(barIndex);
if (volumeProfile == null)
return _volumeProfile[0];
var POCPrice = volumeProfile.POCForBar(barIndex);
var VAHPrice = volumeProfile.HighVAForBar(barIndex);
var VALPrice = volumeProfile.LowVAForBar(barIndex);
if (POCPrice == null)
Output.WriteLine("GetVolumeProfileValues: Volume Profile NoData, barIndex= {0}, DateTime= {1}", barIndex, Bars.Time.Value);
var volumeProfileValues = new VolumeProfileValues
{
POC = (POCPrice == null) ? 0 : POCPrice.Dbl,
VAH = (VAHPrice == null) ? 0 : VAHPrice.Dbl,
VAL = (VALPrice == null) ? 0 : VALPrice.Dbl,
};
volumeProfileValues.VAR = volumeProfileValues.VAH - volumeProfileValues.VAL;
return volumeProfileValues;
}
private void OnTick()
{
if (_djtic == null)
return;
var tickHigh = _djtic.HighValue;
var tickLow = _djtic.LowValue;
var tick = _djtic.CloseValue;
var close = Bars.CloseValue;
_volumeProfile[0] = GetVolumeProfileValues(Bars.FullSymbolData.Current - 1);
m_atr = this.AverageTrueRange(AtrLength);
if (TickExit)
if (TickEntry)
}
}
}
private void OnBar()
{
_isTradingTime.Value = _tradingStartTime <= Bars.TimeValue.TimeOfDay && Bars.TimeValue.TimeOfDay < _tradingEndTime;
if (IBEntry || IBExit || VolumeProfileEntry || VolumeProfileExit || TickEntry || TickExit)
{
_volumeProfile[0] = GetVolumeProfileValues(Bars.FullSymbolData.Current - 1);
}
CheckForExit();
CheckForEntry();
if (Bars.LastBarInSession)
{
OnEndOfDay();
}
UpdateExpertCommentary();
}
private void OnEndOfDay()
{
if (AtrEntry)
{
_atr = this.AverageTrueRange(AtrLength, 0, _dailyDataStream);
}
if (IBEntry)
{
_initialBalanceHigh = null;
_initialBalanceLow = null;
}
if (VolumeProfileEntry || VolumeProfileExit)
{
_volumeProfile[1] = _volumeProfile[0];
}
if (TickEntry || TickExit)
{
_volumeProfile[1] = _volumeProfile[0];
}
}
private void UpdateExpertCommentary()
{
try
{
if (!UseExpertCommentary)
return;
if (TickEntry)
{
ExpertCommentary.WriteLine("Tick Overbought Touches = {0}", _tickOverboughtCounter);
ExpertCommentary.WriteLine("Tick Oversold Touches = {0}", _tickOversoldCounter);
ExpertCommentary.WriteLine("Tick High = {0}", _djtic.HighValue);
ExpertCommentary.WriteLine("Tick Low = {0}", _djtic.LowValue);
}
if (IBEntry)
{
ExpertCommentary.WriteLine("IB High = {0}", ToString(_initialBalanceHigh));
ExpertCommentary.WriteLine("IB Low = {0}", ToString(_initialBalanceLow));
ExpertCommentary.WriteLine("IB Range = {0}", ToString(_initialBalanceHigh - _initialBalanceLow));
ExpertCommentary.WriteLine("IB High Range = {0}", ToString(_initialBalanceHigh - _volumeProfile[0].POC));
ExpertCommentary.WriteLine("IB Low Range = {0}", ToString(_volumeProfile[0].POC - _initialBalanceLow));
}
if (AtrEntry)
{
ExpertCommentary.WriteLine("Daily ATR = {0}", ToString(_atr));
}
if (VolumeProfileEntry || VolumeProfileExit)
{
if (_volumeProfile != null && _volumeProfile[1] != null)
{
ExpertCommentary.WriteLine("Today's VAH = {0}", ToString(_volumeProfile[0].VAH));
ExpertCommentary.WriteLine("Today's POC = {0}", ToString(_volumeProfile[0].POC));
ExpertCommentary.WriteLine("Today's VAL = {0}", ToString(_volumeProfile[0].VAL));
ExpertCommentary.WriteLine("POC Change = {0}", ToString(_volumeProfile[0].POC - _volumeProfile[1].POC));
ExpertCommentary.WriteLine("Yesterday's VAH = {0}", ToString(_volumeProfile[1].VAH));
ExpertCommentary.WriteLine("Yesterday's POC = {0}", ToString(_volumeProfile[1].POC));
ExpertCommentary.WriteLine("Yesterday's VAL = {0}", ToString(_volumeProfile[1].VAL));
ExpertCommentary.WriteLine("Today's VAH Range = {0}", ToString(_volumeProfile[0].VAH - _volumeProfile[0].POC));
ExpertCommentary.WriteLine("Today's VAL Range = {0}", ToString(_volumeProfile[0].POC - _volumeProfile[0].VAL));
ExpertCommentary.WriteLine("Today's VA Range = {0}", ToString(_volumeProfile[0].VAR));
ExpertCommentary.WriteLine("Open Gap = {0}", ToString(m_todaysopen.Value - m_yestclose.Value));
ExpertCommentary.WriteLine("Today's Open = {0}", ToString(m_todaysopen.Value));
ExpertCommentary.WriteLine("Today's High = {0}", ToString(m_todayshigh.Value));
ExpertCommentary.WriteLine("Today's Low = {0}", ToString(m_todayslow.Value));
ExpertCommentary.WriteLine("Yesterday's Close = {0}", ToString(m_yestclose.Value));
ExpertCommentary.WriteLine("Bar Close = {0}", ToString(Bars.CloseValue));
ExpertCommentary.WriteLine("3m ATR = {0}", ToString(m_atr));
ExpertCommentary.WriteLine("Daily ATR = {0}", ToString(_atr));
ExpertCommentary.WriteLine("Profit Target = {0}", ToString(_pt));
ExpertCommentary.WriteLine("Stop Loss = {0}", ToString(_sl));
ExpertCommentary.WriteLine("Profit Target Max = {0}", ToString(_ptf));
ExpertCommentary.WriteLine("Stop Loss Max = {0}", ToString(_slf));
}
}
}
catch (Exception ex)
{
Output.WriteLine("UpdateExpertCommentary Exception: {0}", ex.Message);
}
}
private void CheckForEntry()
{
var time = Bars.Time;
var open = Bars.OpenValue;
var close = Bars.CloseValue;
var openGap = m_todaysopen.Value - m_yestclose.Value;
// Initial Balance Entry
var ibTradeTime = Bars.Time[0].Date.Add(_tradingStartTime).AddHours(1);
var isIbEntryTime = Bars.Time[1] < ibTradeTime && Bars.Time[0] >= ibTradeTime;
if (IBEntry && isIbEntryTime && _volumeProfile[0] != null)
{
var initialStart = time[0].Date.Add(_tradingStartTime);
_initialBalanceHigh = double.MinValue;
_initialBalanceLow = double.MaxValue;
for (var i = 1; i < Bars.CurrentBar; i++)
{
if (time[i] <= initialStart)
break;
_initialBalanceHigh = Math.Max(Bars.High[i], _initialBalanceHigh.Value);
_initialBalanceLow = Math.Min(Bars.Low[i], _initialBalanceLow.Value);
}
var ibRange = _initialBalanceHigh - _initialBalanceLow;
var ibLRange = _volumeProfile[0].POC - _initialBalanceLow;
var ibHRange = _initialBalanceHigh - _volumeProfile[0].POC;
var ihVAR = _volumeProfile[0].VAH - _volumeProfile[0].POC;
var ilVAR = _volumeProfile[0].POC -_volumeProfile[0].VAL;
var iHE = _initialBalanceHigh - _ptf;
var iLE = _initialBalanceLow + _ptf;
var TPOC = _volumeProfile[0].POC;
var TVAH = _volumeProfile[0].VAH;
var TVAL = _volumeProfile[0].VAL;
var YPOC = _volumeProfile[1].POC;
var YVAH = _volumeProfile[1].VAH;
var YVAL = _volumeProfile[1].VAL;
var POCCh = _volumeProfile[0].POC - _volumeProfile[1].POC;
var TO = m_todaysopen.Value;
var YC = m_yestclose.Value;
// Long Entry
// Short Entry
}
// Volume Profile Entry
if (VolumeProfileEntry && _volumeProfile != null && _volumeProfile[0] != null && time[0].TimeOfDay < _tradeEntryEndTime)
{
if (time[0].TimeOfDay < _volumeProfileEntryTime)
return;
_atr = this.AverageTrueRange(AtrLength, 0, _dailyDataStream);
// Long Conditions
// Short Conditions
}
}
private void CheckForExit()
{
_pt = (2.5 + m_atr) * 4;
_sl = (2.5 + m_atr) * 4;
_ptf = 30;
_slf = 30;
var marketPosition = StrategyInfo.MarketPosition;
if (marketPosition == 0)
return;
if (CloseOnEOD)
{
if (Bars.Time[0].TimeOfDay >= _tradingEndTime)
{
if (marketPosition > 0)
_marketOrder[EOrderAction.Sell].Send("EOD LX");
if (marketPosition < 0)
_marketOrder[EOrderAction.BuyToCover].Send("EOD SX");
}
}
if (_pt.HasValue && _ptf.HasValue)
GenerateProfitTargetPt(Math.Min(_pt.Value, _ptf.Value));
if (_sl.HasValue && _slf.HasValue)
GenerateStopLossPt(Math.Min(_sl.Value, _slf.Value));
double ibStopLoss, vpStopLoss;
if (IBExit && _initialBalanceHigh.HasValue && _initialBalanceLow.HasValue)
ibStopLoss = marketPosition > 0 ? _initialBalanceHigh.Value : _initialBalanceLow.Value;
else
ibStopLoss = marketPosition > 0 ? double.MaxValue : double.MinValue;
if (VolumeProfileExit && _volumeProfile[0] != null && m_atr.HasValue)
vpStopLoss = marketPosition > 0 ? _volumeProfile[0].POC + (2 + m_atr.Value) : _volumeProfile[0].POC - (2 + m_atr.Value);
else
vpStopLoss = marketPosition > 0 ? double.MaxValue : double.MinValue;
var stopLoss = marketPosition > 0 ? Math.Min(ibStopLoss, vpStopLoss) : Math.Max(ibStopLoss, vpStopLoss);
if (stopLoss > double.MinValue && stopLoss < double.MaxValue)
GenerateStopLoss(stopLoss);
}
protected override void StopCalc()
{
base.StopCalc();
DataLoader.EndLoadData(_dataLoaderResult);
}
}
}