Mechanism of HasCrossedAbove and HasCrossedBelow
Mechanism of HasCrossedAbove and HasCrossedBelow
07 Dec 2018, 04:13
Hi Traders/Developers, I am having a hard time warping my head around the HasCrossedAbove/HasCrossedBelow. Suppose I have this code:
if (shortMA.Result.HasCrossedAbove(longMA.Result.LastValue, 1)) { ClosePosition(TradeType.Sell); if (!PositionExists(TradeType.Buy)) OpenPosition(TradeType.Buy); } else if (shortMA.Result.HasCrossedBelow(longMA.Result.LastValue, 1)) { ClosePosition(TradeType.Buy); if (!PositionExists(TradeType.Sell)) OpenPosition(TradeType.Sell); }
As usual, I want the MovingAverageCrossOver to happen at OneLastPreviousBar to enter a position on CurrentBar per
if ((shortSMA.Result.Last(0) > longSMA.Result.Last(0)) && (shortSMA.Result.Last(1) <= longSMA.Result.Last(1))) {} if ((shortSMA.Result.Last(0) < longSMA.Result.Last(0)) && (shortSMA.Result.Last(1) >= longSMA.Result.Last(1))) {}
When attached to cBot, HasCrossedAbove(HasCrossedBelow) not only adds a new long(short) position when CrossOver occurs but when the existing long(short) position exits due to TakeProfit, a new long(short) position is added immediately after due to shortMA.Result.Last(1) > longMA.Result.Last(1) even though there is no CrossOver.
It seems to me that HasCrossedAbove(HasCrossedBelow) simply just make one comparison between [shortMA.Result.Last(1) && longMA.Result.Last(1)] and execute the ClosePosition() and OpenPosition() based on that condition only. Would be appreciated if anyone can shed light on this confusion. Thanks.
Replies
d.vietnguyen1011
07 Dec 2018, 04:35
RE:
mparama said:
Try this:
if (shortMA.Result.HasCrossedAbove(longMA.Result, 0))
0 correspond to the LastValue
if (shortMA.Result.HasCrossedAbove(longMA.Result, 1))
1 correspond to the previous bar
Thanks mparama.
Does it opens a new position if [shortMA.Result.LastValue > longMA.Result.LastValue] although there is No [shortMA.Result.Last(1) <= longMA.Result.Last(1)]?
@d.vietnguyen1011
PanagiotisCharalampous
07 Dec 2018, 10:30
Hi Derek,
Can you share the full cBot code as well some steps to reproduce what you see? Maybe the problem is somewhere else.
Best Regards,
Panagiotis
@PanagiotisCharalampous
d.vietnguyen1011
07 Dec 2018, 13:20
( Updated at: 21 Dec 2023, 09:21 )
RE:
Panagiotis Charalampous said:
Hi Derek,
Can you share the full cBot code as well some steps to reproduce what you see? Maybe the problem is somewhere else.
Best Regards,
Panagiotis
Hi Panagiotis, I manage to fix the problem above however, there are some trades that are not taken by the CrossOver. Below is the code and the problem. Thanks for your time!
namespace cAlgo { [Robot(TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)] public class PracticeBot : Robot { // +--------------------------- // | [START] Custom Parameters // +--------------------------- // Robot Name [Parameter("Instance Name", DefaultValue = "EMA_cross")] public string instanceName { get; set; } // Choose the source of calculation [Parameter("ShortMASourcePrice")] public DataSeries shortSource { get; set; } // Choose the source of calculation [Parameter("longMASourcePrice")] public DataSeries longSource { get; set; } // Set Default Lot Size [Parameter("Lot Size", DefaultValue = 0.01)] public double lotSize { get; set; } // Short and Long Moving Average [Parameter("Period SMA #1", DefaultValue = 7, MinValue = 1, MaxValue = 100)] public int shortPeriod { get; set; } [Parameter("Period SMA #2", DefaultValue = 28, MinValue = 1, MaxValue = 100)] public int longPeriod { get; set; } [Parameter("Calculate OnBar", DefaultValue = false)] public bool calculateOnBar { get; set; } // Variables to be initialized in Onstart() private ExponentialMovingAverage shortEMA { get; set; } private ExponentialMovingAverage longEMA { get; set; } [Parameter()] public DataSeries sourceSeries { get; set; } // +--------------------------- // | [END] Custom Parameters // +--------------------------- // +----------------------------- // | [START] MAIN PROGRAM // +----------------------------- protected override void OnStart() { // construct the indicators shortEMA = Indicators.ExponentialMovingAverage(shortSource, shortPeriod); longEMA = Indicators.ExponentialMovingAverage(longSource, longPeriod); } /// <summary> /// This method is called at every candle (bar) close, when it has formed /// </summary> protected override void OnBar() { ManagePositions(); } // [FUNCTION_START] -- Main function to manage Positions private void ManagePositions() { // Generate candle index // index 0 double currentShortMA = shortEMA.Result.Last(0); double currentLongMA = longEMA.Result.Last(0); // index 1 double lastShortMA = shortEMA.Result.Last(1); double lastLongMA = longEMA.Result.Last(1); // index 2 double twoLastShortMA = shortEMA.Result.Last(2); double twoLastLongMA = longEMA.Result.Last(2); // Modify Existing Position ModifyPosition(TradeType.Buy); ModifyPosition(TradeType.Sell); // Check Condition for Up bool twoBarConditionUp = (currentShortMA > currentLongMA + 0.1 * Symbol.PipSize) && (lastShortMA <= lastLongMA); bool threeBarConditionUp = (currentShortMA >= currentLongMA + 0.1 * Symbol.PipSize) && (lastShortMA >= lastLongMA + 0.1 * Symbol.PipSize) && (twoLastShortMA <= twoLastLongMA); // Check Condition for Down bool twoBarConditionDown = (currentShortMA < currentLongMA - 0.1 * Symbol.PipSize) && (lastShortMA >= lastLongMA); bool threeBarConditionDown = (currentShortMA <= currentLongMA - 0.1 * Symbol.PipSize) && (lastShortMA <= lastLongMA - 0.1 * Symbol.PipSize) && (twoLastShortMA >= twoLastLongMA); // || threeBarConditionUp) ((twoBarConditionUp && (sourceSeries.Last(0) > currentShortMA) || threeBarConditionUp)) if (shortEMA.Result.HasCrossedAbove(longEMA.Result, 1)) { if (!PositionExists(TradeType.Buy)) //&& (SourceSeries.LastValue > shortEMA.Result.LastValue)) OpenPosition(TradeType.Buy); ClosePosition(TradeType.Sell); } // if a sell position is already open and signal is buy do nothing //|| threeBarConditionDown) (twoBarConditionDown && (sourceSeries.Last(0) < currentShortMA) || threeBarConditionDown)) if (shortEMA.Result.HasCrossedBelow(longEMA.Result, 1)) { if (!PositionExists(TradeType.Sell)) //&& (SourceSeries.LastValue < shortEMA.Result.LastValue)) OpenPosition(TradeType.Sell); ClosePosition(TradeType.Buy); } } // [Function_START]--Opens a new long/short position private void OpenPosition(TradeType tradeType) { // calculate volume from lot size. double volume = Symbol.QuantityToVolumeInUnits(lotSize); // open a new position ExecuteMarketOrder(tradeType, Symbol, volume, instanceName, 17, 250); } // [Function_END] // [Function_START]--Close Position private void ClosePosition(TradeType tradeType) { Position p = Positions.Find(instanceName, Symbol, type); if (p != null) { ClosePosition(p); } } // [Function_END]--Close Position // [Function_START]-- Retrieve Position by Type to Use Above private bool PositionExists(TradeType tradeType) { var p = Positions.FindAll(instanceName, Symbol, tradeType); if (p.Count() >= 1) { return true; } return false; } // [Function_END]-- Retrieve Position by Type to Use Above // [Function_START]--ModifyTrailingStop private void ModifyPosition(TradeType tradeType) { Position position = Positions.Find(instanceName, Symbol, tradeType); double stopLoss = 0; double takeProfit = 0; if (position != null) { if (position.Pips > 30) { if (tradeType == TradeType.Buy) { stopLoss = Symbol.Bid - 15 * Symbol.PipSize; takeProfit = Symbol.Bid + 50 * Symbol.PipSize; } else if (tradeType == TradeType.Sell) { stopLoss = Symbol.Ask + 15 * Symbol.PipSize; takeProfit = Symbol.Ask - 50 * Symbol.PipSize; } } else if (position.Pips > 50) { if (tradeType == TradeType.Buy) { stopLoss = Symbol.Bid - 25 * Symbol.PipSize; takeProfit = Symbol.Bid + 100 * Symbol.PipSize; } else if (tradeType == TradeType.Sell) { stopLoss = Symbol.Ask + 25 * Symbol.PipSize; takeProfit = Symbol.Ask - 100 * Symbol.PipSize; } } } } // +----------------------------- // | [END] MAIN PROGRAM // +----------------------------- } }
* The positions don't exit by the CrossOver
@d.vietnguyen1011
PanagiotisCharalampous
07 Dec 2018, 14:17
Hi Derek,
Can you post a screenshot of the cBot parameters as well so that I can reproduce on backtesting?
Best Regards,
Panagiotis
@PanagiotisCharalampous
d.vietnguyen1011
07 Dec 2018, 14:18
RE:
Panagiotis Charalampous said:
Hi Derek,
Can you post a screenshot of the cBot parameters as well so that I can reproduce on backtesting?
Best Regards,
Panagiotis
I did it with the default value
@d.vietnguyen1011
d.vietnguyen1011
07 Dec 2018, 14:33
RE:
Panagiotis Charalampous said:
Hi Derek,
Can you post a screenshot of the cBot parameters as well so that I can reproduce on backtesting?
Best Regards,
Panagiotis
I take it on GBPJPY fyi
@d.vietnguyen1011
d.vietnguyen1011
07 Dec 2018, 14:35
RE:
Panagiotis Charalampous said:
Timeframes?
My bad. It's 5-min
@d.vietnguyen1011
PanagiotisCharalampous
07 Dec 2018, 15:11
( Updated at: 21 Dec 2023, 09:21 )
Strange. I ran it on Spotware Beta 3.4 and works fine. See below
However I noticed that your cBot code has an issue and does not build. So I had to fix it. Can you make sure that you do not get any compilation errors and that you are using the latest version?
Best Regards,
Panagiotis
@PanagiotisCharalampous
mparama
07 Dec 2018, 04:29
Try this:
if (shortMA.Result.HasCrossedAbove(longMA.Result, 0))
0 correspond to the LastValue
if (shortMA.Result.HasCrossedAbove(longMA.Result, 1))
1 correspond to the previous bar
@mparama