Help with Null Reference and Pending Order Type
Help with Null Reference and Pending Order Type
21 Mar 2022, 05:53
Hi guys,
I keep getting an error "Crashed in Positions.Closed with NullReferenceException: Object reference not set to an instance of an object" and I am struggling to find the error. I have gone through and put print functions everywhere to try and find the last place it calls before it errors but I can find it. I have been running it on EUR/USD 1 hr just to trouble shoot the code etc and it keeps giving the error in the bar period e.g 9:32, not when the new bar is called ?? sorry if the code is a bit clunky.
The other part of my question is, is it possible to call a pendingordertype for buys and sells ?? instead of stop, stoplimit etc.
something like this (the PendingOrder and OrderDirection thing I cant get it to work) ??
protected void Orderbytype(PendingOrder OrderDirection)
{
foreach (var order in PendingOrders)
{
if (order.Label == InstanceName && order.SymbolName == SymbolName)
{
double newPrice = Symbol.Ask + 5 * Symbol.PipSize;
ModifyPendingOrder(order, newPrice, order.StopLossPips, order.TakeProfitPips, order.ExpirationTime);
}
}
}
Full code for the Null reference error.
using System;
using System.Linq;
using cAlgo.API;
using cAlgo.API.Indicators;
using cAlgo.API.Internals;
using cAlgo.Indicators;
namespace cAlgo
{
[Robot(TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
public class EMATrendBuyonlyOpenOrders : Robot
{
#region User defined parameters
[Parameter("Instance Name", DefaultValue = "EMAtrend")]
public string InstanceName { get; set; }
[Parameter("Open Sell Positions", Group = "Positions and Orders", DefaultValue = 1, MinValue = 1, MaxValue = 5)]
public int possell { get; set; }
[Parameter("Open Buy Positions", Group = "Positions and Orders", DefaultValue = 1, MinValue = 1, MaxValue = 5)]
public int posbuy { get; set; }
[Parameter("Open Total Positions", Group = "Positions and Orders", DefaultValue = 1, MinValue = 1, MaxValue = 10)]
public int postotal { get; set; }
[Parameter("Enable Add Spread to SL", Group = "Positions and Orders", DefaultValue = false)]
public bool enableAddSpread { get; set; }
[Parameter("% per trade", Group = "Money Management", DefaultValue = 2, MinValue = 0.5, MaxValue = 4, Step = 0.5)]
public double PerTrade { get; set; }
[Parameter("ATR Periods", Group = "Money Management", DefaultValue = 14)]
public int atrPeriodsbuy { get; set; }
[Parameter("Slow MA Source", Group = "Moving Averages")]
public DataSeries Sourcema1 { get; set; }
[Parameter("Slow MA Period", Group = "Moving Averages", DefaultValue = 200, MinValue = 100, MaxValue = 400)]
public int Periodsma1 { get; set; }
[Parameter("Slow MA Type", Group = "Moving Averages", DefaultValue = MovingAverageType.Exponential)]
public MovingAverageType ma1Type { get; set; }
[Parameter("Fast MA Source", Group = "Moving Averages")]
public DataSeries Sourcema2 { get; set; }
[Parameter("Fast MA Period", Group = "Moving Averages", DefaultValue = 50, MinValue = 10, MaxValue = 80)]
public int Periodsma2 { get; set; }
[Parameter("Fast MA Type", Group = "Moving Averages", DefaultValue = MovingAverageType.Exponential)]
public MovingAverageType ma2Type { get; set; }
[Parameter("Source", Group = "ADX")]
public DataSeries SourceADX { get; set; }
[Parameter("ADX Periods", Group = "ADX", DefaultValue = 14, MinValue = 1, MaxValue = 25)]
public int PeriodsADX { get; set; }
[Parameter("ADX Low Limit", Group = "ADX", DefaultValue = 20, MinValue = 5, MaxValue = 40)]
public int ADXlow { get; set; }
[Parameter("Source", Group = "RSI")]
public DataSeries SourceRSI { get; set; }
[Parameter("Periods", Group = "RSI", DefaultValue = 14, MinValue = 1, MaxValue = 25)]
public int PeriodsRSI { get; set; }
[Parameter("RSI Over Sold", Group = "RSI", DefaultValue = 40, MinValue = 1, MaxValue = 60)]
public int RSILow { get; set; }
[Parameter("RSI Over Bought", Group = "RSI", DefaultValue = 60, MinValue = 40, MaxValue = 99)]
public int RSIHigh { get; set; }
[Parameter("RSI MA Period", Group = "RSI", DefaultValue = 5, MinValue = 1, MaxValue = 15)]
public int RSImaPeriod { get; set; }
[Parameter("RSI Lookback Period", Group = "RSI", DefaultValue = 5, MinValue = 1, MaxValue = 15)]
public int RSIlookback { get; set; }
/*
[Parameter("MACD LongCycle", Group = "MACD", DefaultValue = 26, MinValue = 1, MaxValue = 100)]
public int LongCycle { get; set; }
[Parameter("MACD ShortCycle", Group = "MACD", DefaultValue = 12, MinValue = 1, MaxValue = 100)]
public int ShortCycle { get; set; }
[Parameter("MACD Period", Group = "MACD", DefaultValue = 9, MinValue = 1, MaxValue = 100)]
public int MACDPeriod { get; set; }
*/
[Parameter("Normal SL Type", Group = "Stop Loss Info", DefaultValue = StopLossType.ATR)]
public StopLossType stoplossType { get; set; }
[Parameter("Trailing SL Type", Group = "Stop Loss Info", DefaultValue = TrailingStopType.ATR)]
public TrailingStopType trailingStopType { get; set; }
[Parameter("ATR Multiplier Stop Loss ", Group = "Normal SL & TP", DefaultValue = 1.5, MinValue = 1, MaxValue = 4, Step = 0.5)]
public double SLATR { get; set; }
[Parameter("ATR Multiplier Take Profit ", Group = "Normal SL & TP", DefaultValue = 1.5, MinValue = 1, MaxValue = 4, Step = 0.5)]
public double TPATR { get; set; }
[Parameter("Manual Stop Loss (pips)", Group = "Normal SL & TP", DefaultValue = 100, MinValue = 5, Step = 1)]
public double stopLoss { get; set; }
[Parameter("Trigger (pips)", Group = "TSL Optimiser", DefaultValue = 5.0, MinValue = 1, MaxValue = 20)]
public double TriggerPips { get; set; }
[Parameter("Trail SL (pips)", Group = "TSL Optimiser", DefaultValue = 10.0, MinValue = 1, MaxValue = 100)]
public double TrailSLPips { get; set; }
[Parameter("Trail TP (pips)", Group = "TSL Optimiser ", DefaultValue = 5.0, MinValue = 1, MaxValue = 100)]
public double TrailTPPips { get; set; }
[Parameter("ATR TSL Periods", Group = "TSL ATR", DefaultValue = 21)]
public int atrPeriodsSL { get; set; }
[Parameter("ATR TSL Multiplier", Group = "TSL ATR", DefaultValue = 2, MinValue = 1, MaxValue = 5, Step = 0.5)]
public double atrMultiplierSL { get; set; }
#endregion
#region Indicator declarations
private MovingAverage ma1 { get; set; }
private MovingAverage ma2 { get; set; }
private RelativeStrengthIndex rsi { get; set; }
private AverageTrueRange atrbuy { get; set; }
private AverageTrueRange atrTSL { get; set; }
///private MacdCrossOver _MACD { get; set; }
private MovingAverage rsiMA { get; set; }
private AverageDirectionalMovementIndexRating _ADX { get; set; }
Symbol currentSymbol;
Position currentPosition;
double? newStopLoss = 0;
double? newTakeProfit = 0;
public double ATRMinimuStopLoss;
#endregion
#region cTrader events
protected override void OnStart()
{
// construct the indicators
ma1 = Indicators.MovingAverage(Sourcema1, Periodsma1, ma1Type);
ma2 = Indicators.MovingAverage(Sourcema2, Periodsma2, ma2Type);
atrbuy = Indicators.AverageTrueRange(atrPeriodsbuy, MovingAverageType.Exponential);
atrTSL = Indicators.AverageTrueRange(atrPeriodsSL, MovingAverageType.Exponential);
rsi = Indicators.RelativeStrengthIndex(SourceRSI, PeriodsRSI);
rsiMA = Indicators.MovingAverage(rsi.Result, RSImaPeriod, MovingAverageType.Exponential);
_ADX = Indicators.AverageDirectionalMovementIndexRating(PeriodsADX);
///_MACD = Indicators.MacdCrossOver(LongCycle, ShortCycle, MACDPeriod);
ATRMinimuStopLoss = 5;
Positions.Closed += OnPositionsClosed;
}
protected override void OnTick()
{
}
/*
ATRTrailingStop();
MomentumTrailingStop();
Optimiser();
*/
protected override void OnBar()
{
var currentTime = Server.Time;
var day = Server.Time.DayOfWeek;
int positionCount = CountPositions();
int positionCountbuy = CountPositionsbuy();
int positionCountsell = CountPositionssell();
int Orderscount = CountOrders();
/// Bar values
var PCV1 = Bars.ClosePrices.Last(1);
var PCV2 = Bars.ClosePrices.Last(2);
var PLV = Bars.LowPrices.Last(1);
var PHV = Bars.HighPrices.Last(1);
var GreenBar = Bars.ClosePrices.Last(1) - Bars.OpenPrices.Last(1);
/// should be greater than 0 for green result
var RedBar = Bars.OpenPrices.Last(1) - Bars.ClosePrices.Last(1);
// should be greater than 0 for red result
/// EMA Values
var ma1Prev = ma1.Result.Last(1);
var ma1Prev2 = ma1.Result.Last(2);
var ma1Prev3 = ma1.Result.Last(3);
var ma2Prev = ma2.Result.Last(1);
var ma2Prev2 = ma2.Result.Last(2);
var ma2Prev3 = ma2.Result.Last(3);
/// ADX and RSI Values
var ADXRvalue = _ADX.ADXR.LastValue;
var diminus = _ADX.DIMinus.LastValue;
var diplus = _ADX.DIPlus.LastValue;
var rsiMAValue = rsiMA.Result.Last(1);
var RSIvalue = rsi.Result.Last(1);
/*
var MACDLine = _MACD.MACD.Last(1);
var PrevMACDLine = _MACD.MACD.Last(2);
var Signal = _MACD.Signal.Last(1);
var PrevSignal = _MACD.Signal.Last(2);
*/
if (day == DayOfWeek.Monday || day == DayOfWeek.Tuesday || day == DayOfWeek.Thursday || day == DayOfWeek.Friday || day == DayOfWeek.Saturday || day == DayOfWeek.Sunday)
{
/// buy baby
if (ma2Prev > ma1Prev && rsi.Result.HasCrossedBelow(RSILow, RSIlookback) && ADXRvalue > ADXlow)
{
if (!IsPositionOpenByType(TradeType.Buy) && positionCount < postotal && Orderscount == 0)
{
ClosePositions(TradeType.Sell);
CloseAllOrders();
var PrevATR = Math.Round((atrbuy.Result.Last(1) / Symbol.PipSize), 3);
var newTakeProfit = TPATR * PrevATR;
var PerTradeadjust = PerTrade / 100;
var TradeAmount = (Account.Equity * PerTradeadjust) / (PrevATR * Symbol.PipValue);
TradeAmount = Symbol.NormalizeVolumeInUnits(TradeAmount, RoundingMode.Down);
var targetPrice = Bars.OpenPrices.Last(2);
var newStopLoss = normalstoploss() + addSpreadToStopLoss();
Print("StopLoss value: {0},", newStopLoss);
PlaceStopLimitOrder(TradeType.Buy, SymbolName, TradeAmount, targetPrice, 2, InstanceName, newStopLoss, newTakeProfit);
}
else if (PCV1 < PCV2 && RedBar >= 0 && !IsPositionOpenByType(TradeType.Buy) && positionCount < postotal && Orderscount > 0)
{
ClosePositions(TradeType.Sell);
foreach (var order in PendingOrders)
{
if (order.Label == InstanceName && order.SymbolName == SymbolName && order != null)
{
var PrevATR = Math.Round((atrbuy.Result.Last(1) / Symbol.PipSize), 3);
var targetPrice = Bars.OpenPrices.LastValue;
var newStopLoss = normalstoploss() + addSpreadToStopLoss();
var newTakeProfit = TPATR * PrevATR;
ModifyPendingOrder(order, targetPrice, newStopLoss, newTakeProfit);
Print("Modifyied StopLoss value: {0},", newStopLoss);
}
}
}
}
///fire sale all needs redoing
else /*
else
if (EmaPrev < SmaPrev)
{
if (!IsPositionOpenByType(TradeType.Sell) && positionCount <= postotal)
{
ClosePositions(TradeType.Buy);
OpenPosition(InstanceName, TradeType.Sell);
PlaceLimitOrder(TradeType.Sell, SymbolName, TradeAmt(), entryPriceshort, InstanceName, stopLoss, TAKEP);
}
else if
{
foreach (var order in PendingOrders)
{
if (order.Label == label && order.SymbolName == SymbolName && order != null)
{
var targetPrice = Bars.OpenPrices(1);
if (PCV1 > PCV2 && GreenBar > 0 && order.TradeType == TradeType.Sell)
{
ModifyPendingOrder(order, targetPrice);
ModifyPendingOrder(order, double targetPrice, double? stopLossPips, double? takeProfitPips)
}
}
}
}
}
*/
{
CloseAllOrders();
}
}
}
protected override void OnStop()
{
// unused
}
#endregion
#region Private subs
/*
protected void Orderbytype(PendingOrder OrderDirection)
{
foreach (var order in PendingOrders)
{
if (order.Label == InstanceName && order.SymbolName == SymbolName)
{
double newPrice = Symbol.Ask + 5 * Symbol.PipSize;
ModifyPendingOrder(order, newPrice, order.StopLossPips, order.TakeProfitPips, order.ExpirationTime);
}
}
}
*/
private void CloseAllOrders()
{
Print("CloseAllOrders", "CloseAllOrders");
foreach (var order in PendingOrders)
{
if (order.Label == InstanceName && order.SymbolName == SymbolName)
{
CancelPendingOrder(order);
}
}
}
/*
private void OpenPosition(string Label, TradeType TradeDirection)
{
//Calculate Trade Amount base on the ATR
var PrevATR = Math.Round((atrbuy.Result.Last(1) / Symbol.PipSize), 3);
var PerTradeadjust = PerTrade / 100;
var TradeAmount = (Account.Equity * PerTradeadjust) / (PrevATR * Symbol.PipValue);
TradeAmount = Symbol.NormalizeVolumeInUnits(TradeAmount, RoundingMode.Down);
ExecuteMarketOrder(TradeDirection, SymbolName, TradeAmount, InstanceName, SLATR * PrevATR, TPATR * PrevATR);
/// Print to the log all the trade data
///Print("RSI Value: {0}, EMA Prev: {1}, EMA Prev 3 {2}, Price Close - EMA: {3}, Stop Loss in Pips {4}", RSIvalue, EMAPrev, EMAPrev3, abc123, SL2EMAbuy);
}
*/
private int CountPositions()
{
Print("CountPositionstotal", "CountPositionstotal");
var positions = Positions.FindAll(InstanceName, SymbolName);
return positions.Length;
}
private int CountPositionsbuy()
{
Print("CountPositionsbuy", "CountPositionsbuy");
var positions = Positions.FindAll(InstanceName, SymbolName, TradeType.Buy);
return positions.Length;
}
private int CountPositionssell()
{
Print("CountPositionssell", "CountPositionssell");
var positions = Positions.FindAll(InstanceName, SymbolName, TradeType.Sell);
return positions.Length;
}
private int CountOrders()
{
Print("CountOrders", "CountOrders");
int count = 0;
foreach (var order in PendingOrders)
{
if (order.Label == InstanceName && order.SymbolName == SymbolName)
{
count++;
}
}
return count;
}
private void ClosePositions(TradeType type)
{
Print("ClosePositions,", type);
var p = Positions.Find(InstanceName, this.Symbol, type);
if (p != null)
{
ClosePosition(p);
}
}
private bool IsPositionOpenByType(TradeType type)
{
Print("IsPositionOpenByType,", type);
var p = Positions.FindAll(InstanceName, Symbol, type);
if (p.Count() >= posbuy)
{
return true;
}
return false;
}
bool isNearTarget()
{
Print("Trailing stop,", trailingStopType);
if (this.currentPosition.TradeType == TradeType.Buy)
{
if (currentSymbol.Bid > this.currentPosition.TakeProfit - (this.currentSymbol.PipSize * this.TriggerPips))
return true;
}
else
{
if (currentSymbol.Ask < this.currentPosition.TakeProfit + (this.currentSymbol.PipSize * this.TriggerPips))
return true;
}
return false;
}
private void Optimiser()
{
if (trailingStopType != TrailingStopType.Optimiser)
{
return;
}
Print("Trailing stop,", trailingStopType);
foreach (var pos in Positions)
{
this.currentSymbol = Symbols.GetSymbol(SymbolName);
this.currentPosition = pos;
if (isNearTarget())
{
if (currentPosition.TradeType == TradeType.Buy)
{
newStopLoss = currentSymbol.Bid - (this.currentSymbol.PipSize * this.TrailSLPips);
newTakeProfit = currentSymbol.Bid + (this.currentSymbol.PipSize * this.TrailTPPips);
}
else
{
newStopLoss = currentSymbol.Ask + (this.currentSymbol.PipSize * this.TrailSLPips);
newTakeProfit = currentSymbol.Ask - (this.currentSymbol.PipSize * this.TrailTPPips);
}
if (newStopLoss == 0 || newTakeProfit == 0)
return;
ModifyPosition(currentPosition, newStopLoss, newTakeProfit);
}
}
}
private void ATRTrailingStop()
{
if (trailingStopType != TrailingStopType.ATR)
{
return;
}
Print("Trailing stop,", trailingStopType);
var positions = Positions.FindAll(InstanceName, SymbolName);
if (positions.Length > 0)
{
double atrPips = (atrTSL.Result.LastValue / Symbol.PipSize) * atrMultiplierSL;
atrPips = Math.Round(atrPips, 1);
///Print(atrPips);
foreach (var position in positions)
{
if (position.TradeType == TradeType.Buy && Symbol.Bid - (atrPips * Symbol.PipSize) > position.StopLoss)
{
//Print("Old sl price: " + position.StopLoss);
ModifyPosition(position, Symbol.Bid - (atrPips * Symbol.PipSize), position.TakeProfit);
//Print("New sl price: " + position.StopLoss);
}
else if (position.TradeType == TradeType.Sell && Symbol.Ask + (atrPips * Symbol.PipSize) < position.StopLoss)
{
//Print("Old sl price: " + position.EntryPrice);
ModifyPosition(position, Symbol.Ask + (atrPips * Symbol.PipSize), position.TakeProfit);
//Print("New sl price: " + position.StopLoss);
}
}
}
}
private void MomentumTrailingStop()
{
if (trailingStopType != TrailingStopType.Momentum)
{
return;
}
Print("Trailing stop,", trailingStopType);
var positions = Positions.FindAll(InstanceName, SymbolName);
{
if (positions.Length > 0)
{
foreach (var position in positions)
{
if (position.TradeType == TradeType.Buy && position.StopLoss < position.EntryPrice)
{
var newStopLossPrice = Symbol.Ask - (Symbol.PipSize * stopLoss);
if (newStopLossPrice > position.StopLoss)
{
ModifyPosition(position, newStopLossPrice, position.TakeProfit);
}
}
else if (position.TradeType == TradeType.Sell && position.StopLoss > position.EntryPrice)
{
var newStopLossPrice = Symbol.Bid + (Symbol.PipSize * stopLoss);
if (newStopLossPrice < position.StopLoss)
{
ModifyPosition(position, newStopLossPrice, position.TakeProfit);
}
}
}
}
}
}
private double addSpreadToStopLoss()
{
if (enableAddSpread)
{
var spread = Math.Round(Symbol.Spread / Symbol.PipSize, 1);
Print("Spread added to stop loss (", spread, ")");
return spread;
}
return 0;
}
private double normalstoploss()
{
if (stoplossType == StopLossType.ATR)
{
double atrSLPips = (atrbuy.Result.LastValue / Symbol.PipSize) * SLATR;
atrSLPips = Math.Round(atrSLPips, 1);
if (atrSLPips < ATRMinimuStopLoss)
{
atrSLPips = ATRMinimuStopLoss;
}
return atrSLPips;
}
else if (stoplossType == StopLossType.CandleLow)
{
var newStopLoss = Math.Round((Math.Abs((Bars.ClosePrices.Last(2) - Bars.LowPrices.Last(1))) / Symbol.PipSize), 3);
return newStopLoss;
}
else
{
return stopLoss;
}
}
private void OnPositionsClosed(PositionClosedEventArgs args)
{
double SPREAD;
SPREAD = (double)((int)Math.Round(Symbol.Spread / Symbol.PipSize, 5));
// check if the position has been closed due to stoploss or takeprofit or any other(stop out etc)
if (args.Reason == PositionCloseReason.StopLoss)
{
Print("PID: [ {0} ] Stoploss Hit {1} || Gain/Loss {2}Pips / $ {3} || Spread:{4} || {5} {6}:{7}:{8} ", LastResult.Position.Id, SymbolName, LastResult.Position.Pips, LastResult.Position.NetProfit, SPREAD, Server.Time.DayOfWeek, Server.Time.Hour, Server.Time.Minute, Server.Time.Second);
}
else if (args.Reason == PositionCloseReason.TakeProfit)
{
Print("PID: [ {0} ] Take Profit Hit {1} || Gain/Loss {2}Pips / $ {3} || Spread:{4} || {5} {6}:{7}:{8}", LastResult.Position.Id, SymbolName, LastResult.Position.Pips, LastResult.Position.NetProfit, SPREAD, Server.Time.DayOfWeek, Server.Time.Hour, Server.Time.Minute, Server.Time.Second);
}
else if (args.Reason == PositionCloseReason.Closed)
{
Print("PID: [ {0} ] Exit Trade {1} || Gain/Loss {2}Pips / $ {3} || Spread:{4} || {5} {6}:{7}:{8}", LastResult.Position.Id, SymbolName, LastResult.Position.Pips, LastResult.Position.NetProfit, SPREAD, Server.Time.DayOfWeek, Server.Time.Hour, Server.Time.Minute, Server.Time.Second);
}
else if (args.Reason == PositionCloseReason.StopOut)
{
Print("PID: [ {0} ] StopOut {1} || Gain/Loss {2}Pips / $ {3} || Spread:{4} || {5} {6}:{7}:{8}", LastResult.Position.Id, SymbolName, LastResult.Position.Pips, LastResult.Position.NetProfit, SPREAD, Server.Time.DayOfWeek, Server.Time.Hour, Server.Time.Minute, Server.Time.Second);
}
}
public enum TrailingStopType
{
Momentum,
ATR,
Optimiser,
None
}
public enum StopLossType
{
Manual,
ATR,
CandleLow
}
#endregion
}
}
amusleh
21 Mar 2022, 08:42
Hi,
Inside position closed event handler you are using LastResult, it's Position property is null:
Replace the above handler with yours, run your cBot, and you will that it prints "LastResult.Position is null" on logs.
To avoid such issues I strongly recommend you to learn C# basics before developing a cBot/Indicator.
@amusleh