Topics
Forum Topics not found
Replies
amusleh
18 Jun 2021, 16:57
( Updated at: 18 Jun 2021, 16:58 )
Hi,
You should not use Print method inside property setter method, this works fine:
using cAlgo.API;
namespace cAlgo.Robots
{
[Robot(TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
public class Baseline : Robot
{
[Parameter("Risk (%)", DefaultValue = 2.0, MinValue = 1.0, MaxValue = 5.0, Step = 1.0, Group = "Risk Management")]
public double RiskPercentage
{
get
{
return riskPercentage;
}
set
{
riskPercentage = SetRisk(value);
}
}
private double riskPercentage;
protected override void OnStart()
{
RiskPercentage = 4.0;
}
protected override void OnBar()
{
}
protected override void OnTick()
{
}
private double SetRisk(double value)
{
return value;
}
}
}
And Strategy is null when you access it inside setter method, that can also cause this issue, because OnStart is not called yet.
@amusleh
amusleh
16 Jun 2021, 11:53
( Updated at: 16 Jun 2021, 11:55 )
Hi,
You can open a buy/sell market order by using ExecuteMarketOrder method, and you can pass the stop loss/take profit in Pips.
The order will be executed based on symbol bid/ask price, check the code examples of Position.
You can use OnBar method on a Renko chart to execute your orders per bar, or use the OnTick method to count the Pips by your self.
@amusleh
amusleh
14 Jun 2021, 14:33
Hi,
I created a MTF exponential moving average for you:
using cAlgo.API;
using cAlgo.API.Internals;
using System;
namespace cAlgo
{
[Indicator(IsOverlay = true, TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
public class MTFEMA : Indicator
{
private Bars _baseTimeFrameBars;
private DataSeries _baseSeries;
private double _multiplier;
private bool _isInitialized;
private int _baseTimeFramePreviousIndex;
private double _baseTimeFramePreviousEma;
[Parameter(DefaultValue = 14)]
public double Periods { get; set; }
[Parameter("Source", DefaultValue = DataSource.Close)]
public DataSource Source { get; set; }
[Parameter("Base Time Frame")]
public TimeFrame BaseTimeFrame { get; set; }
[Output("Main")]
public IndicatorDataSeries Result { get; set; }
protected override void Initialize()
{
_baseTimeFrameBars = MarketData.GetBars(BaseTimeFrame);
_baseSeries = GetSeries(Source);
_multiplier = 2 / (Periods + 1);
}
public override void Calculate(int index)
{
var baseTimeFrameIndex = _baseTimeFrameBars.OpenTimes.GetIndexByTime(Bars[index].OpenTime);
if (baseTimeFrameIndex < Periods) return;
if (!_isInitialized)
{
Result[index] = GetAverage(baseTimeFrameIndex);
_isInitialized = true;
}
else
{
Result[index] = (_baseTimeFrameBars[baseTimeFrameIndex].Close - _baseTimeFramePreviousEma) * _multiplier + _baseTimeFramePreviousEma;
}
if (baseTimeFrameIndex != _baseTimeFramePreviousIndex)
{
_baseTimeFramePreviousIndex = baseTimeFrameIndex;
_baseTimeFramePreviousEma = Result[index];
}
}
private double GetAverage(int index)
{
var lastIndex = index - Periods;
double sum = 0;
for (var i = index; i > lastIndex; i--)
{
sum += _baseSeries[i];
}
return sum / Periods;
}
private DataSeries GetSeries(DataSource dataSource)
{
switch (dataSource)
{
case DataSource.Open:
return _baseTimeFrameBars.OpenPrices;
case DataSource.High:
return _baseTimeFrameBars.HighPrices;
case DataSource.Low:
return _baseTimeFrameBars.LowPrices;
case DataSource.Close:
return _baseTimeFrameBars.ClosePrices;
case DataSource.Volume:
return _baseTimeFrameBars.TickVolumes;
case DataSource.Typical:
return _baseTimeFrameBars.TypicalPrices;
case DataSource.Weighted:
return _baseTimeFrameBars.WeightedPrices;
case DataSource.Median:
return _baseTimeFrameBars.MedianPrices;
default:
throw new ArgumentOutOfRangeException("dataSource");
}
}
}
public enum DataSource
{
Open,
High,
Low,
Close,
Volume,
Typical,
Median,
Weighted
}
}
I checked it gives same result like built-in EMA, only the last bar value might be different because it waits for bar to finish then it updates the value as it should consider other time frames data, hopefully this will help you.
@amusleh
amusleh
14 Jun 2021, 12:06
Hi,
You can't use index for another time frame bars data, in your code you used the current chart bars index to get another time frame bars data: barsTF1.ClosePrices[index]
Try this:
using cAlgo.API;
using cAlgo.API.Indicators;
using cAlgo.API.Internals;
using System;
namespace cAlgo.Indicators
{
[Indicator(IsOverlay = true, TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
public class TripleEMA : Indicator
{
[Parameter("EMA Fast", DefaultValue = 50)]
public int Periods { get; set; }
[Parameter("EMA Slow", DefaultValue = 100)]
public int Periods1 { get; set; }
[Parameter("EMA Trend", DefaultValue = 200)]
public int Periods2 { get; set; }
[Parameter("EMA Trend", DefaultValue = 100)]
public int Periods3 { get; set; }
[Parameter("TimeFrame", DefaultValue = "Daily")]
public TimeFrame EMATimeframe1 { get; set; }
[Output("EMA1", LineColor = "Blue")]
public IndicatorDataSeries EMA1 { get; set; }
[Output("EMA2", LineColor = "Red")]
public IndicatorDataSeries EMA2 { get; set; }
[Output("EMA3", LineColor = "Yellow")]
public IndicatorDataSeries EMA3 { get; set; }
private Bars series1;
private Bars barsTF1;
private ExponentialMovingAverage Ema1;
private ExponentialMovingAverage Ema2;
private ExponentialMovingAverage Ema3;
private ExponentialMovingAverage Ema4;
private IndicatorDataSeries _iDataSeries1;
protected override void Initialize()
{
//series1 = MarketData.GetSeries(EMATimeframe1);
series1 = MarketData.GetBars(EMATimeframe1);
Ema1 = Indicators.ExponentialMovingAverage(series1.ClosePrices, Periods);
Ema2 = Indicators.ExponentialMovingAverage(series1.ClosePrices, Periods1);
Ema3 = Indicators.ExponentialMovingAverage(series1.ClosePrices, Periods2);
barsTF1 = MarketData.GetBars(TimeFrame.Hour4);
_iDataSeries1 = CreateDataSeries();
Ema4 = Indicators.ExponentialMovingAverage(_iDataSeries1, Periods3);
}
public override void Calculate(int index)
{
var index1 = GetIndexByDate(series1, Bars.OpenTimes[index]);
if (index1 != -1)
{
EMA1[index] = Ema1.Result[index1];
}
var index2 = GetIndexByDate(series1, Bars.OpenTimes[index]);
if (index2 != -1)
{
EMA2[index] = Ema2.Result[index2];
}
var index3 = GetIndexByDate(series1, Bars.OpenTimes[index]);
if (index3 != -1)
{
EMA3[index] = Ema3.Result[index3];
}
var barsTF1Index = barsTF1.OpenTimes.GetIndexByTime(Bars[index].OpenTime);
_iDataSeries1[index] = barsTF1.ClosePrices[barsTF1Index] - (High(index) + Low(index)) / 2;
Print("EMA : " + Ema4.Result[index]);
}
private int GetIndexByDate(Bars series, DateTime time)
{
for (int i = series.Count - 1; i > 0; i--)
{
if (time == series.OpenTimes[i])
return i;
}
return -1;
}
private double High(int index)
{
double high = Bars.HighPrices[index - 10];
for (int i = index - 10 + 1; i <= index; i++)
{
if (Bars.HighPrices[i] > high)
high = Bars.HighPrices[i];
}
return high;
}
private double Low(int index)
{
double low = Bars.LowPrices[index - 10];
for (int i = index - 10 + 1; i <= index; i++)
{
if (Bars.LowPrices[i] < low)
low = Bars.LowPrices[i];
}
return low;
}
}
}
@amusleh
amusleh
13 Jun 2021, 08:27
Hi,
To use WinForms on your cBot/Indicator, you have to follow these steps:
- Add System.Windows.Forms Reference to your cBot/Indicator project
- Change your cBot/Indicator AccessRights to FullAccess
- Add a Windows Form to your cBot/Indicator project by right clicking on your project in VS, then select Add -> Form
- Design your form on VS WinFroms Designer
- To communicate between your cBot/Indicator and Form you can pass your indicator/cBot to the form via its constructor parameter, or use an adapter object
- You must execute the Form ShowDialog method inside a separate thread, because this method blocks the thread until the form is closed you have to use a separate thread, and not use the cBot/Indicator main execution thread, also the thread must have STA ApartmentState
- Build your cBot/Indicator project from VS not cTrader, because of the changes you made on references and adding new form, you can build it from cTrader but the first build after adding the form and making changes on project references must be done by VS
As an example you can check my WinForms Test cBot sample:
Clone it from Github or download it as a zip file, extract the content on a new folder inside your cTrader cAlgo/Robots folder, it will appear in your cTrader automate cBots list, re-build it and run it.
Open it with VS to see the cBot full code.
@amusleh
amusleh
08 Jun 2021, 12:04
Hi,
The positions collections will be updated immediately after sending a position execution request, try this sample code:
using cAlgo.API;
using cAlgo.API.Internals;
using System.Text;
namespace cAlgo.Robots
{
[Robot(TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
public class RSIRangeRobot : Robot
{
protected override void OnStart()
{
ExecuteMarketOrder(TradeType.Buy, SymbolName, Symbol.VolumeInUnitsMin);
}
protected override void OnTick()
{
foreach (var position in Positions)
{
var stringBuilder = new StringBuilder();
stringBuilder.AppendFormat("Before Execution: {0}", Positions.Count);
ExecuteMarketOrder(TradeType.Buy, SymbolName, Symbol.VolumeInUnitsMin);
stringBuilder.AppendFormat(" | After Execution: {0}", Positions.Count);
Print(stringBuilder);
}
}
}
}
@amusleh
amusleh
08 Jun 2021, 11:46
Hi,
There are several issues on your code, I recommend you to take a look on Automate API references and multi time frame indicator samples.
I fixed some of the issues for you:
using cAlgo.API;
using cAlgo.API.Indicators;
namespace cAlgo.Indicators
{
[Indicator(IsOverlay = true, AccessRights = AccessRights.None)]
public class MTFGRaBCandles : Indicator
{
[Parameter("MA Period", DefaultValue = 300)]
public int maPeriod { get; set; }
[Parameter("MA Type", DefaultValue = MovingAverageType.Simple)]
public MovingAverageType MAType { get; set; }
[Parameter("Candle width", DefaultValue = 5)]
public int CandleWidth { get; set; }
[Parameter("Wick width", DefaultValue = 1)]
public int WickWidth { get; set; }
[Parameter("Above up color", DefaultValue = "LimeGreen")]
public string AboveUpColor { get; set; }
[Parameter("Above down color", DefaultValue = "DarkGreen")]
public string AboveDownColor { get; set; }
[Parameter("Middle up color", DefaultValue = "LightBlue")]
public string MiddleUpColor { get; set; }
[Parameter("Middle down color", DefaultValue = "DodgerBlue")]
public string MiddleDownColor { get; set; }
[Parameter("Below up color", DefaultValue = "Tomato")]
public string BelowUpColor { get; set; }
[Parameter("Below down color", DefaultValue = "Crimson")]
public string BelowDownColor { get; set; }
[Output("High Moving Average", Color = Colors.Red, LineStyle = LineStyle.Lines)]
public IndicatorDataSeries HMaResult { get; set; }
[Output("Low Moving Average", Color = Colors.LimeGreen, LineStyle = LineStyle.Lines)]
public IndicatorDataSeries LMaResult { get; set; }
[Output("Middle Moving Average", Color = Colors.Blue, LineStyle = LineStyle.Lines)]
public IndicatorDataSeries MaResult { get; set; }
private MovingAverage _Hma;
private MovingAverage _Lma;
private MovingAverage _ma;
private Bars D1;
private Color _AboveUpColor;
private Color _AboveDownColor;
private Color _MiddleUpColor;
private Color _MiddleDownColor;
private Color _BelowUpColor;
private Color _BelowDownColor;
protected override void Initialize()
{
D1 = MarketData.GetBars(TimeFrame.Daily);
_Hma = Indicators.MovingAverage(D1.HighPrices, maPeriod, MAType);
_Lma = Indicators.MovingAverage(D1.LowPrices, maPeriod, MAType);
_ma = Indicators.MovingAverage(D1.ClosePrices, maPeriod, MAType);
_AboveUpColor = GetColor(AboveUpColor);
_AboveDownColor = GetColor(AboveDownColor);
_MiddleUpColor = GetColor(MiddleUpColor);
_MiddleDownColor = GetColor(MiddleDownColor);
_BelowUpColor = GetColor(BelowUpColor);
_BelowDownColor = GetColor(BelowDownColor);
}
public override void Calculate(int index)
{
var dailyIndex = D1.OpenTimes.GetIndexByTime(Bars[index].OpenTime);
var open = D1.OpenPrices[dailyIndex];
var high = D1.HighPrices[dailyIndex];
var low = D1.LowPrices[dailyIndex];
var close = D1.ClosePrices[dailyIndex];
var HMA = _Hma.Result[index];
var LMA = _Lma.Result[index];
var MA = _ma.Result[index];
HMaResult[index] = HMA;
LMaResult[index] = LMA;
MaResult[index] = MA;
Color color = Color.Black;
if (close > HMA)
color = open > close ? _AboveDownColor : _AboveUpColor;
if (close < LMA)
color = open > close ? _BelowDownColor : _BelowUpColor;
if (close >= LMA && close <= HMA)
color = open > close ? _MiddleDownColor : _MiddleUpColor;
Chart.DrawTrendLine("candle" + index, index, open, index, close, color, CandleWidth, LineStyle.Solid);
Chart.DrawTrendLine("line" + index, index, high, index, low, color, WickWidth, LineStyle.Solid);
}
private Color GetColor(string colorString, int alpha = 255)
{
var color = colorString[0] == '#' ? Color.FromHex(colorString) : Color.FromName(colorString);
return Color.FromArgb(alpha, color);
}
}
}
You can't start developing indicators/cBots without a solid knowledge of C# basics and Automate API.
If you can't develop your indicator you can post a job request or contact one of our consultants.
@amusleh
amusleh
05 Jun 2021, 19:30
RE:
traderfxmaster007 said:
Faulting application name: cTrader.exe, version: 4.0.14.48970, time stamp: 0xafdfe7f4
Faulting module name: PresentationCore.ni.dll, version: 4.8.4110.0, time stamp: 0x5de7179c
Exception code: 0xc00000fd
Fault offset: 0x0000000000350324
Faulting process id: 0x8d4
Faulting application start time: 0x01d756152ce5d722
Faulting application path: C:\Users\Administrator\AppData\Local\Apps\2.0\6PBGL0GK.DOV\JTW5VCAE.AMT\icma..ader_7ef853fc4bdbd138_0004.0000_0ba06d2b7438f083\cTrader.exe
Faulting module path: C:\windows\assembly\NativeImages_v4.0.30319_64\PresentationCore\461b892934d24d029a6ef6d42101af09\PresentationCore.ni.dll
Report Id: 44b3c76c-c45b-11eb-85ad-f15c940a3a9d
Hi,
Its not what I asked you to post, please run the cBot code I posted on my latest post and run it, when it crashed a message will appear on cTrader cBot logs tab, copy it and post it here.
@amusleh
amusleh
04 Jun 2021, 07:41
RE: RE: RE:
traderfxmaster007 said:
Sir Amusleh,
Same Error Code:
Crashed in OnTick with NullReferenceException: Object reference not set to an instance of an object.
Hi,
Can you copy the full logs tab data and post here? that's the default cTrader error message, I need the message that the Print method shows.
Something is wrong with your ManagePositions method.
Please use the below code this time, it will display more detailed data regarding the exception:
using cAlgo.API;
using cAlgo.API.Indicators;
using cAlgo.API.Internals;
using System;
using System.Diagnostics;
using System.Linq;
using System.Text;
namespace cAlgo
{
[Robot(TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
public class MiaEMARibbon : Robot
{
#region User defined parameters
[Parameter("Instance Name", DefaultValue = "20 Rangers")]
public string InstanceName { get; set; }
[Parameter("Percentage Risk Model?", Group = "Money Management", DefaultValue = true)]
public bool volPercentBool { get; set; }
[Parameter("Scale Out?", Group = "Money Management", DefaultValue = true)]
public bool ScaleOut { get; set; }
[Parameter("Risk %", Group = "Money Management", DefaultValue = 1.5, MinValue = 1, MaxValue = 5)]
public double volPercent { get; set; }
[Parameter("Volume Quantity", Group = "Money Management", DefaultValue = 2000, MinValue = 1000, Step = 1000)]
public int volQty { get; set; }
[Parameter("StopLoss (*ATR)", Group = "Protection", DefaultValue = 1.5, Step = 0.1, MinValue = 1, MaxValue = 5)]
public double ATRStopLoss { get; set; }
[Parameter("TakeProfit (*ATR)", Group = "Protection", DefaultValue = 1.0, Step = 0.1, MinValue = 1, MaxValue = 5)]
public double ATRTakeProfit { get; set; }
[Parameter("BreakEven", Group = "Protection", DefaultValue = true)]
public bool BreakEven { get; set; }
[Parameter("BreakEvenTrigger (*ATR)", Group = "Protection", DefaultValue = 1.0, Step = 0.1, MinValue = 1, MaxValue = 5)]
public double TriggerPips { get; set; }
[Parameter("Locked in Profit", Group = "Protection", DefaultValue = 3.0, MinValue = 1.0)]
public double AddPips { get; set; }
[Parameter("Use Trailing Stop", Group = "Protection", DefaultValue = true)]
public bool UseTrailingStop { get; set; }
[Parameter("Trailing Stop Trigger (*ATR)", Group = "Protection", DefaultValue = 1.5, Step = 0.1, MinValue = 1, MaxValue = 5)]
public double TrailingStopTrigger { get; set; }
[Parameter("Trailing Stop Step (*ATR)", Group = "Protection", DefaultValue = 2.0, Step = 0.1, MinValue = 1, MaxValue = 5)]
public double TrailingStopStep { get; set; }
[Parameter("Close on Weekend?", Group = "Filter", DefaultValue = true)]
public bool CloseOnWeekend { get; set; }
[Parameter("Allowable Slippage", Group = "Filter", DefaultValue = 3.0, MinValue = 0.5, Step = 0.1)]
public double Slippage { get; set; }
[Parameter("Max Allowable Spread", Group = "Filter", DefaultValue = 2.0, MinValue = 0.1, MaxValue = 100.0, Step = 0.1)]
public double MaxSpread { get; set; }
[Parameter("Calculate OnBar?", Group = "Filter", DefaultValue = true)]
public bool CalculateOnBar { get; set; }
#endregion User defined parameters
#region Indicator declarations
private ExponentialMovingAverage EMA_1 { get; set; }
private ExponentialMovingAverage EMA_2 { get; set; }
private ExponentialMovingAverage EMA_3 { get; set; }
private ExponentialMovingAverage EMA_4 { get; set; }
private ExponentialMovingAverage EMA_5 { get; set; }
private ExponentialMovingAverage EMA_6 { get; set; }
private ExponentialMovingAverage EMA_7 { get; set; }
private ExponentialMovingAverage EMA_8 { get; set; }
private ExponentialMovingAverage EMA_9 { get; set; }
private ExponentialMovingAverage EMA_10 { get; set; }
private AverageTrueRange ATR;
private double SPREAD;
private int volume;
private string Comment;
private int lastbar;
private double StopLoss;
private double TakeProfit;
#endregion Indicator declarations
#region Calculate Volume
private int CalculateVolume(double stop_loss)
{
int result;
switch (volPercentBool)
{
case true:
double costPerPip = (double)((int)(Symbol.PipValue * 100000));
double posSizeForRisk = Math.Round((Account.Balance * (volPercent / 100)) / (stop_loss * costPerPip), 2);
double posSizeToVol = (Math.Round(posSizeForRisk * 100000, 0));
Print("costperppip : $ {0} || Lot : {1} || Volume : {2}", costPerPip, posSizeForRisk, posSizeToVol);
result = (int)Symbol.NormalizeVolumeInUnits(posSizeToVol, RoundingMode.ToNearest);
result = result > 150000 ? 150000 : result;
result = result == 1000 ? 2000 : result;
Print("{0}% of Account Balance [ $ {1} ] used for Volume: {2} || Risk : $ {3}", volPercent, Account.Balance, result, (StopLoss * costPerPip * result) / 100000);
break;
default:
result = volQty;
Print("Volume Quantity Used! : {0}", result);
break;
}
return result;
}
#endregion Calculate Volume
#region Standard event handlers
/// This is called when the robot first starts, it is only called once.
protected override void OnStart()
{
ATR = Indicators.AverageTrueRange(14, MovingAverageType.Exponential);
EMA_1 = Indicators.ExponentialMovingAverage(Bars.ClosePrices, 5);
EMA_2 = Indicators.ExponentialMovingAverage(Bars.ClosePrices, 7);
EMA_3 = Indicators.ExponentialMovingAverage(Bars.ClosePrices, 9);
EMA_4 = Indicators.ExponentialMovingAverage(Bars.ClosePrices, 11);
EMA_5 = Indicators.ExponentialMovingAverage(Bars.ClosePrices, 13);
EMA_6 = Indicators.ExponentialMovingAverage(Bars.ClosePrices, 30);
EMA_7 = Indicators.ExponentialMovingAverage(Bars.ClosePrices, 35);
EMA_8 = Indicators.ExponentialMovingAverage(Bars.ClosePrices, 40);
EMA_9 = Indicators.ExponentialMovingAverage(Bars.ClosePrices, 45);
EMA_10 = Indicators.ExponentialMovingAverage(Bars.ClosePrices, 50);
StopLoss = Math.Round((ATR.Result.Last(lastbar)) * ATRStopLoss / Symbol.PipSize, 0);
TakeProfit = Math.Round((ATR.Result.Last(lastbar)) * ATRTakeProfit / Symbol.PipSize, 0);
volume = CalculateVolume(StopLoss);
SPREAD = Math.Round(Symbol.Spread / Symbol.PipSize, 2);
Comment = "Chris Trend Trading ";
if (CalculateOnBar)
lastbar = 1;
else
lastbar = 0;
// Subscribe to the Trade Closing event
Positions.Closed += OnPositionsClosed;
}
/// This event handler is called every tick or every time the price changes for the symbol.
protected override void OnTick()
{
try
{
ManagePositions();
}
catch (Exception ex)
{
Print(ex.GetLog());
//Stop();
}
}
/// a special event handler that is called each time a new bar is drawn on chart.
/// if you want your robot to act only when the previous bar is closed, this standard handler is where you put your main trading code.
protected override void OnBar()
{
try
{
ManagePositions();
CloseHalf();
MoveToBreakEven();
SetTrailingStop();
}
catch (Exception ex)
{
Print(ex.GetLog());
//Stop();
}
}
/// a special Robot class member that handles situations with errors.
protected override void OnError(Error error)
{
Print("Error Code {0} || {1} {2}:{3}:{4}", error.Code, Server.Time.DayOfWeek, Server.Time.Hour, Server.Time.Minute, Server.Time.Second);
}
#endregion Standard event handlers
#region Logic
private void ManagePositions()
{
/// if there is no buy position open, open one
if (IsPositionOpenByType(TradeType.Buy) == false && Extreme() == false && BuyEntry() == true && EntryBar() == true)
{
if (Trader_Bullish() == false && Investor_Bullish() == true)
{
OpenPosition(TradeType.Buy);
}
else if (Trader_Bullish() == true && Bars.ClosePrices.Last(lastbar + 1) < Bars.OpenPrices.Last(lastbar + 1))
{
OpenPosition(TradeType.Buy);
}
}
/// if there is no sell position open, open one
else if (IsPositionOpenByType(TradeType.Sell) == false && Extreme() == false && SellEntry() == true && EntryBar() == true)
{
if (Trader_Bearish() == false && Investor_Bearish() == true)
{
OpenPosition(TradeType.Sell);
}
else if (Trader_Bearish() == true && Bars.ClosePrices.Last(lastbar + 1) > Bars.OpenPrices.Last(lastbar + 1))
{
OpenPosition(TradeType.Sell);
}
}
/// Call custom class method to Close Open Position
if (IsPositionOpenByType(TradeType.Buy) == true && BuyExit() == true)
ClosePosition(TradeType.Buy);
else if (IsPositionOpenByType(TradeType.Sell) == true && SellExit() == true)
ClosePosition(TradeType.Sell);
}
#endregion Logic
#region Scale Out
private void CloseHalf()
{
var positions = Positions.FindAll(InstanceName.ToString(), SymbolName);
foreach (var position in positions)
{
var Secured = position.TradeType == TradeType.Buy ? position.StopLoss - position.EntryPrice : position.EntryPrice - position.StopLoss;
var HalfVol = Math.Round(Symbol.NormalizeVolumeInUnits(((position.VolumeInUnits) / 2), RoundingMode.ToNearest), 0);
if (ScaleOut == true && position.VolumeInUnits >= 2000 && (Secured / Symbol.PipSize) <= AddPips && position.Pips >= (ATR.Result.Last(lastbar) * ATRTakeProfit) / Symbol.PipSize)
{
ClosePosition(position, HalfVol);
Print("[ {0} ] Scale Out {1} || New Volume: {2} || Gain/Loss {3} Pips / $ {4} || {5} {6}:{7}:{8}", LastResult.Position.Id, SymbolName, position.VolumeInUnits, LastResult.Position.Pips, LastResult.Position.NetProfit, Server.Time.DayOfWeek, Server.Time.Hour, Server.Time.Minute, Server.Time.Second);
}
}
}
#endregion Scale Out
#region BreakEven
/// Call custom class method to move StopLoss to BreakEven
private void MoveToBreakEven()
{
var positions = Positions.FindAll(InstanceName.ToString(), SymbolName);
foreach (var position in positions)
{
var desiredNetProfitInDepositAsset = AddPips * Symbol.PipValue * position.VolumeInUnits;
var desiredGrossProfitInDepositAsset = desiredNetProfitInDepositAsset - position.Commissions * 2 - position.Swap;
var quoteToDepositRate = Symbol.PipValue / Symbol.PipSize;
var priceDifference = desiredGrossProfitInDepositAsset / (position.VolumeInUnits * quoteToDepositRate);
var priceAdjustment = GetPriceAdjustmentByTradeType(position.TradeType, priceDifference);
var breakEvenLevel = position.EntryPrice + priceAdjustment;
var roundedBreakEvenLevel = RoundPrice(breakEvenLevel, position.TradeType);
var stopposition = position.TradeType == TradeType.Buy ? position.EntryPrice - position.StopLoss : position.StopLoss - position.EntryPrice;
if (BreakEven == true && stopposition > 0 && position.Pips >= (ATR.Result.Last(lastbar) * TriggerPips) / Symbol.PipSize)
{
ModifyPosition(position, roundedBreakEvenLevel, position.TakeProfit);
Print("[ {0} ] Breakeven {1} || {2} {3}:{4}:{5}", LastResult.Position.Id, SymbolName, Server.Time.DayOfWeek, Server.Time.Hour, Server.Time.Minute, Server.Time.Second);
}
}
}
#endregion BreakEven
#region TrailingStop
private void SetTrailingStop()
{
var sellPositions = Positions.FindAll(InstanceName, SymbolName, TradeType.Sell);
foreach (Position position in sellPositions)
{
double distance = position.EntryPrice - Symbol.Ask;
if (distance < (ATR.Result.Last(lastbar) * TrailingStopTrigger))
continue;
double newStopLossPrice = Symbol.Ask + (ATR.Result.Last(lastbar) * TrailingStopStep);
var newStopLoss = RoundPrice(newStopLossPrice, position.TradeType);
if (UseTrailingStop == true && (position.StopLoss == null || newStopLossPrice < position.StopLoss))
ModifyPosition(position, newStopLoss, position.TakeProfit);
if (LastResult.IsSuccessful)
Print("[ {0} ] Trailing {1} || New StopLoss: {2} || {3} {4}:{5}:{6}", LastResult.Position.Id, SymbolName, LastResult.Position.StopLoss, Server.Time.DayOfWeek, Server.Time.Hour, Server.Time.Minute, Server.Time.Second);
}
var buyPositions = Positions.FindAll(InstanceName, SymbolName, TradeType.Buy);
foreach (Position position in buyPositions)
{
double distance = Symbol.Bid - position.EntryPrice;
if (distance < (ATR.Result.Last(lastbar) * TrailingStopTrigger))
continue;
double newStopLossPrice = Symbol.Bid - (ATR.Result.Last(lastbar) * TrailingStopStep);
var newStopLoss = RoundPrice(newStopLossPrice, position.TradeType);
if (UseTrailingStop == true && (position.StopLoss == null || newStopLossPrice > position.StopLoss))
ModifyPosition(position, newStopLoss, position.TakeProfit);
if (LastResult.IsSuccessful)
Print("[ {0} ] Trailing {1} || New StopLoss: {2} || {3} {4}:{5}:{6}", LastResult.Position.Id, SymbolName, LastResult.Position.StopLoss, Server.Time.DayOfWeek, Server.Time.Hour, Server.Time.Minute, Server.Time.Second);
}
}
#endregion TrailingStop
#region Open Trade
/// Call custom class method to send a market order || open a new position
private void OpenPosition(TradeType type)
{
var Pos = Positions.FindAll(InstanceName.ToString(), SymbolName);
if (Pos.Count() == 0 && Server.Time.DayOfWeek <= DayOfWeek.Friday && Server.Time.Hour <= 19 && SPREAD <= MaxSpread)
{
if (ScaleOut)
ExecuteMarketRangeOrder(type, this.Symbol.Name, volume, Slippage, Symbol.Bid, InstanceName.ToString(), StopLoss, 0, Comment);
else
ExecuteMarketRangeOrder(type, this.Symbol.Name, volume, Slippage, Symbol.Bid, InstanceName.ToString(), StopLoss, TakeProfit, Comment);
if (LastResult.IsSuccessful)
Print("[ {0} ] Open {1} {2} || Volume:{3} || Spread:{4} || {5} {6}:{7}:{8}", LastResult.Position.Id, type, SymbolName, LastResult.Position.VolumeInUnits, SPREAD, Server.Time.DayOfWeek, Server.Time.Hour, Server.Time.Minute, Server.Time.Second);
}
}
#endregion Open Trade
#region Close Trade
/// Standard event handler that triggers upon position closing.
private void ClosePosition(TradeType type)
{
var p = Positions.Find(InstanceName.ToString(), SymbolName, type);
if (p != null)
{
ClosePosition(p);
Print("[ {0} ] Close {1} {2} || Volume:{3} || Spread:{4} || Gain/Loss {5}Pips / $ {6} || {7} {8}:{9}:{10}", LastResult.Position.Id, type, SymbolName, LastResult.Position.VolumeInUnits, SPREAD, LastResult.Position.Pips, LastResult.Position.NetProfit, Server.Time.DayOfWeek, Server.Time.Hour,
Server.Time.Minute, Server.Time.Second);
}
else if (CloseOnWeekend == true && p != null && Server.Time.DayOfWeek == DayOfWeek.Friday && Server.Time.Hour >= 21 && Server.Time.Minute >= 30)
{
ClosePosition(p);
Print("[ {0} ] Close {1} on Weekend || Gain/Loss {1}Pips / $ {2} || {3} {4}:{5}:{6}", LastResult.Position.Id, SymbolName, LastResult.Position.Pips, LastResult.Position.NetProfit, Server.Time.DayOfWeek, Server.Time.Hour, Server.Time.Minute, Server.Time.Second);
}
}
/// Check for opened position
private bool IsPositionOpenByType(TradeType type)
{
var p = Positions.FindAll(InstanceName.ToString(), SymbolName, type);
if (p.Count() > 0 || p.Count() != 0)
return true;
return false;
}
private void OnPositionsClosed(PositionClosedEventArgs args)
{
// check if the position has been closed due to stoploss or takeprofit or any other(stop out etc)
if (args.Reason == PositionCloseReason.StopLoss)
{
Print("[ {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("[ {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);
}
}
#endregion Close Trade
#region Check for Setups
//////////////////////////////////////////////////////////////////////////
///////////////////////// Check for Setups //////////////////////////////
////////////////////////////////////////////////////////////////////////
private bool Trader_Bullish()
{
if (EMA_1.Result.Last(lastbar) >= EMA_2.Result.Last(lastbar) && EMA_2.Result.Last(lastbar) >= EMA_3.Result.Last(lastbar) && EMA_3.Result.Last(lastbar) >= EMA_4.Result.Last(lastbar) && EMA_4.Result.Last(lastbar) >= EMA_5.Result.Last(lastbar))
return true;
return false;
}
private bool Trader_Bearish()
{
if (EMA_1.Result.Last(lastbar) <= EMA_2.Result.Last(lastbar) && EMA_2.Result.Last(lastbar) <= EMA_3.Result.Last(lastbar) && EMA_3.Result.Last(lastbar) <= EMA_4.Result.Last(lastbar) && EMA_4.Result.Last(lastbar) <= EMA_5.Result.Last(lastbar))
return true;
return false;
}
private bool Investor_Bullish()
{
if (EMA_6.Result.Last(lastbar) >= EMA_7.Result.Last(lastbar) && EMA_7.Result.Last(lastbar) >= EMA_8.Result.Last(lastbar) && EMA_8.Result.Last(lastbar) >= EMA_9.Result.Last(lastbar) && EMA_9.Result.Last(lastbar) >= EMA_10.Result.Last(lastbar))
return true;
return false;
}
private bool Investor_Bearish()
{
if (EMA_6.Result.Last(lastbar) <= EMA_7.Result.Last(lastbar) && EMA_7.Result.Last(lastbar) <= EMA_8.Result.Last(lastbar) && EMA_8.Result.Last(lastbar) <= EMA_9.Result.Last(lastbar) && EMA_9.Result.Last(lastbar) <= EMA_10.Result.Last(lastbar))
return true;
return false;
}
private bool BuyEntry()
{
if (Bars.ClosePrices.Last(lastbar) > Bars.OpenPrices.Last(lastbar) && Bars.LowPrices.Last(lastbar) < EMA_3.Result.Last(lastbar) && Bars.ClosePrices.Last(lastbar) > EMA_1.Result.Last(lastbar) && Bars.ClosePrices.Last(lastbar) > EMA_5.Result.Last(lastbar) && Bars.ClosePrices.Last(lastbar) > EMA_6.Result.Last(lastbar) && Bars.ClosePrices.Last(lastbar) > EMA_10.Result.Last(lastbar))
return true;
return false;
}
private bool SellEntry()
{
if (Bars.ClosePrices.Last(lastbar) < Bars.OpenPrices.Last(lastbar) && Bars.HighPrices.Last(lastbar) > EMA_3.Result.Last(lastbar) && Bars.ClosePrices.Last(lastbar) < EMA_1.Result.Last(lastbar) && Bars.ClosePrices.Last(lastbar) < EMA_5.Result.Last(lastbar) && Bars.ClosePrices.Last(lastbar) < EMA_6.Result.Last(lastbar) && Bars.ClosePrices.Last(lastbar) < EMA_10.Result.Last(lastbar))
return true;
return false;
}
private bool BuyExit()
{
if (IsPositionOpenByType(TradeType.Buy) == true && EMA_1.Result.Last(lastbar) < EMA_2.Result.Last(lastbar) && EMA_1.Result.Last(lastbar) < EMA_3.Result.Last(lastbar) && Bars.ClosePrices.Last(lastbar) < EMA_5.Result.Last(lastbar))
return true;
else if (IsPositionOpenByType(TradeType.Buy) == true && Bars.ClosePrices.Last(lastbar + 1) == Bars.LowPrices.Last(lastbar + 1) && Bars.ClosePrices.Last(lastbar + 2) == Bars.LowPrices.Last(lastbar + 2))
return true;
return false;
}
private bool SellExit()
{
if (IsPositionOpenByType(TradeType.Sell) == true && EMA_1.Result.Last(lastbar) > EMA_2.Result.Last(lastbar) && EMA_1.Result.Last(lastbar) > EMA_3.Result.Last(lastbar) && Bars.ClosePrices.Last(lastbar) > EMA_5.Result.Last(lastbar))
return true;
else if (IsPositionOpenByType(TradeType.Sell) == true && Bars.ClosePrices.Last(lastbar + 1) == Bars.HighPrices.Last(lastbar + 1) && Bars.ClosePrices.Last(lastbar + 2) == Bars.HighPrices.Last(lastbar + 2))
return true;
return false;
}
private bool Extreme()
{
if (Math.Abs(EMA_1.Result.Last(lastbar) - EMA_5.Result.Last(lastbar)) > ATR.Result.Last(lastbar) * 1.618 || Math.Abs(EMA_5.Result.Last(lastbar) - EMA_6.Result.Last(lastbar)) > ATR.Result.Last(lastbar) * 1.382 || Math.Abs(EMA_6.Result.Last(lastbar) - EMA_10.Result.Last(lastbar)) > ATR.Result.Last(lastbar) * 1.618)
return true;
return false;
}
private bool EntryBar()
{
if (Math.Abs(Bars.OpenPrices.Last(lastbar) - Bars.ClosePrices.Last(lastbar)) > Math.Abs(Bars.HighPrices.Last(lastbar) - Bars.LowPrices.Last(lastbar)) * 0.618)
return true;
return false;
}
#endregion Check for Setups
#region RoundPrice
////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////
private double RoundPrice(double price, TradeType tradeType)
{
var multiplier = Math.Pow(10, Symbol.Digits);
if (tradeType == TradeType.Buy)
return Math.Ceiling(price * multiplier) / multiplier;
return Math.Floor(price * multiplier) / multiplier;
}
private static double GetPriceAdjustmentByTradeType(TradeType tradeType, double priceDifference)
{
if (tradeType == TradeType.Buy)
return priceDifference;
return -priceDifference;
}
#endregion RoundPrice
}
public static class ExceptionExtensions
{
public static string GetLog(this Exception exception)
{
return exception.GetLog(null, false);
}
private static string GetLog(this Exception exception, string intend, bool isInnerException)
{
var stringBuilder = new StringBuilder();
intend = intend ?? string.Empty;
if (isInnerException)
{
stringBuilder.AppendLine();
stringBuilder.AppendFormat("{0}InnerException:", intend);
}
else
{
var systemType = Environment.Is64BitOperatingSystem ? "64-bit" : "32-bit";
stringBuilder.AppendLine();
stringBuilder.AppendFormat("OS Version: {0}", Environment.OSVersion.VersionString);
stringBuilder.AppendLine();
stringBuilder.AppendFormat("System Type: {0}", systemType);
}
stringBuilder.AppendLine();
stringBuilder.AppendFormat("{0}Source: {1}", intend, exception.Source);
stringBuilder.AppendLine();
stringBuilder.AppendFormat("{0}Message: {1}", intend, exception.Message);
stringBuilder.AppendLine();
stringBuilder.AppendFormat("{0}TargetSite: {1}", intend, exception.TargetSite);
stringBuilder.AppendLine();
stringBuilder.AppendFormat("{0}Type: {1}", intend, exception.GetType());
stringBuilder.AppendLine();
var stackTrace = exception.GetStackTrace(intend);
stringBuilder.AppendLine(stackTrace);
stringBuilder.AppendLine();
if (exception.InnerException != null)
{
var innerExceptionIntent = new string(' ', intend.Length + 4);
var innerExceptionSummary = exception.InnerException.GetLog(innerExceptionIntent, true);
stringBuilder.Append(innerExceptionSummary);
}
return stringBuilder.ToString();
}
public static string GetStackTrace(this Exception exception)
{
return exception.GetStackTrace(null);
}
private static string GetStackTrace(this Exception exception, string intend)
{
if (string.IsNullOrEmpty(exception.StackTrace))
{
return string.Empty;
}
var stackTrace = new StackTrace(exception, true);
var frames = stackTrace.GetFrames();
if (frames == null || !frames.Any())
{
return string.Empty;
}
var stringBuilder = new StringBuilder();
stringBuilder.AppendFormat("{0}StackTrace:", intend);
stringBuilder.AppendLine();
var tracesIntend = new string(' ', string.IsNullOrEmpty(intend) ? 4 : intend.Length + 4);
foreach (var stackFram in frames)
{
var fileName = stackFram.GetFileName();
fileName = !string.IsNullOrEmpty(fileName)
? fileName.Substring(fileName.LastIndexOf(@"\", StringComparison.InvariantCultureIgnoreCase) + 1)
: string.Empty;
stringBuilder.AppendFormat("{0}File: {1} | Line: {2} | Col: {3} | Offset: {4} | Method: {5}", tracesIntend, fileName, stackFram.GetFileLineNumber(), stackFram.GetFileColumnNumber(), stackFram.GetILOffset(), stackFram.GetMethod());
stringBuilder.AppendLine();
}
return stringBuilder.ToString();
}
}
}
@amusleh
amusleh
02 Jun 2021, 18:59
RE: RE: RE: RE:
chris07 said:
Hi amusleh,
I have contacted the developer and he responded that if the line levels of the fibo tool were interactive they could all be moved individually. Thus the question is if only the outer lines can be made adjustable, like it is the case for every fibonacci tool. You apparently have done that for your own custom fibo tool. Could you give some hints on how you have achieved that? I know your code is proprietary, too, so I respect if you want to keep this "close to your vest".
Hi,
My code is not proprietary, the indicator is open source on Github:
@amusleh
amusleh
02 Jun 2021, 16:58
Hi,
I backtested your cBot and it worked fine, if cBot got stopped then it means something is wrong with your code.
Please use this cBot code instead:
using cAlgo.API;
using cAlgo.API.Indicators;
using cAlgo.API.Internals;
using System;
using System.Linq;
namespace cAlgo
{
[Robot(TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
public class MiaEMARibbon : Robot
{
#region User defined parameters
[Parameter("Instance Name", DefaultValue = "20 Rangers")]
public string InstanceName { get; set; }
[Parameter("Percentage Risk Model?", Group = "Money Management", DefaultValue = true)]
public bool volPercentBool { get; set; }
[Parameter("Scale Out?", Group = "Money Management", DefaultValue = true)]
public bool ScaleOut { get; set; }
[Parameter("Risk %", Group = "Money Management", DefaultValue = 1.5, MinValue = 1, MaxValue = 5)]
public double volPercent { get; set; }
[Parameter("Volume Quantity", Group = "Money Management", DefaultValue = 2000, MinValue = 1000, Step = 1000)]
public int volQty { get; set; }
[Parameter("StopLoss (*ATR)", Group = "Protection", DefaultValue = 1.5, Step = 0.1, MinValue = 1, MaxValue = 5)]
public double ATRStopLoss { get; set; }
[Parameter("TakeProfit (*ATR)", Group = "Protection", DefaultValue = 1.0, Step = 0.1, MinValue = 1, MaxValue = 5)]
public double ATRTakeProfit { get; set; }
[Parameter("BreakEven", Group = "Protection", DefaultValue = true)]
public bool BreakEven { get; set; }
[Parameter("BreakEvenTrigger (*ATR)", Group = "Protection", DefaultValue = 1.0, Step = 0.1, MinValue = 1, MaxValue = 5)]
public double TriggerPips { get; set; }
[Parameter("Locked in Profit", Group = "Protection", DefaultValue = 3.0, MinValue = 1.0)]
public double AddPips { get; set; }
[Parameter("Use Trailing Stop", Group = "Protection", DefaultValue = true)]
public bool UseTrailingStop { get; set; }
[Parameter("Trailing Stop Trigger (*ATR)", Group = "Protection", DefaultValue = 1.5, Step = 0.1, MinValue = 1, MaxValue = 5)]
public double TrailingStopTrigger { get; set; }
[Parameter("Trailing Stop Step (*ATR)", Group = "Protection", DefaultValue = 2.0, Step = 0.1, MinValue = 1, MaxValue = 5)]
public double TrailingStopStep { get; set; }
[Parameter("Close on Weekend?", Group = "Filter", DefaultValue = true)]
public bool CloseOnWeekend { get; set; }
[Parameter("Allowable Slippage", Group = "Filter", DefaultValue = 3.0, MinValue = 0.5, Step = 0.1)]
public double Slippage { get; set; }
[Parameter("Max Allowable Spread", Group = "Filter", DefaultValue = 2.0, MinValue = 0.1, MaxValue = 100.0, Step = 0.1)]
public double MaxSpread { get; set; }
[Parameter("Calculate OnBar?", Group = "Filter", DefaultValue = true)]
public bool CalculateOnBar { get; set; }
#endregion User defined parameters
#region Indicator declarations
private ExponentialMovingAverage EMA_1 { get; set; }
private ExponentialMovingAverage EMA_2 { get; set; }
private ExponentialMovingAverage EMA_3 { get; set; }
private ExponentialMovingAverage EMA_4 { get; set; }
private ExponentialMovingAverage EMA_5 { get; set; }
private ExponentialMovingAverage EMA_6 { get; set; }
private ExponentialMovingAverage EMA_7 { get; set; }
private ExponentialMovingAverage EMA_8 { get; set; }
private ExponentialMovingAverage EMA_9 { get; set; }
private ExponentialMovingAverage EMA_10 { get; set; }
private AverageTrueRange ATR;
private double SPREAD;
private int volume;
private string Comment;
private int lastbar;
private double StopLoss;
private double TakeProfit;
#endregion Indicator declarations
#region Calculate Volume
private int CalculateVolume(double stop_loss)
{
int result;
switch (volPercentBool)
{
case true:
double costPerPip = (double)((int)(Symbol.PipValue * 100000));
double posSizeForRisk = Math.Round((Account.Balance * (volPercent / 100)) / (stop_loss * costPerPip), 2);
double posSizeToVol = (Math.Round(posSizeForRisk * 100000, 0));
Print("costperppip : $ {0} || Lot : {1} || Volume : {2}", costPerPip, posSizeForRisk, posSizeToVol);
result = (int)Symbol.NormalizeVolumeInUnits(posSizeToVol, RoundingMode.ToNearest);
result = result > 150000 ? 150000 : result;
result = result == 1000 ? 2000 : result;
Print("{0}% of Account Balance [ $ {1} ] used for Volume: {2} || Risk : $ {3}", volPercent, Account.Balance, result, (StopLoss * costPerPip * result) / 100000);
break;
default:
result = volQty;
Print("Volume Quantity Used! : {0}", result);
break;
}
return result;
}
#endregion Calculate Volume
#region Standard event handlers
/// This is called when the robot first starts, it is only called once.
protected override void OnStart()
{
ATR = Indicators.AverageTrueRange(14, MovingAverageType.Exponential);
EMA_1 = Indicators.ExponentialMovingAverage(Bars.ClosePrices, 5);
EMA_2 = Indicators.ExponentialMovingAverage(Bars.ClosePrices, 7);
EMA_3 = Indicators.ExponentialMovingAverage(Bars.ClosePrices, 9);
EMA_4 = Indicators.ExponentialMovingAverage(Bars.ClosePrices, 11);
EMA_5 = Indicators.ExponentialMovingAverage(Bars.ClosePrices, 13);
EMA_6 = Indicators.ExponentialMovingAverage(Bars.ClosePrices, 30);
EMA_7 = Indicators.ExponentialMovingAverage(Bars.ClosePrices, 35);
EMA_8 = Indicators.ExponentialMovingAverage(Bars.ClosePrices, 40);
EMA_9 = Indicators.ExponentialMovingAverage(Bars.ClosePrices, 45);
EMA_10 = Indicators.ExponentialMovingAverage(Bars.ClosePrices, 50);
StopLoss = Math.Round((ATR.Result.Last(lastbar)) * ATRStopLoss / Symbol.PipSize, 0);
TakeProfit = Math.Round((ATR.Result.Last(lastbar)) * ATRTakeProfit / Symbol.PipSize, 0);
volume = CalculateVolume(StopLoss);
SPREAD = Math.Round(Symbol.Spread / Symbol.PipSize, 2);
Comment = "Chris Trend Trading ";
if (CalculateOnBar)
lastbar = 1;
else
lastbar = 0;
// Subscribe to the Trade Closing event
Positions.Closed += OnPositionsClosed;
}
/// This event handler is called every tick or every time the price changes for the symbol.
protected override void OnTick()
{
try
{
ManagePositions();
}
catch (Exception ex)
{
Print(ex);
Stop();
}
}
/// a special event handler that is called each time a new bar is drawn on chart.
/// if you want your robot to act only when the previous bar is closed, this standard handler is where you put your main trading code.
protected override void OnBar()
{
try
{
ManagePositions();
CloseHalf();
MoveToBreakEven();
SetTrailingStop();
}
catch (Exception ex)
{
Print(ex);
Stop();
}
}
/// a special Robot class member that handles situations with errors.
protected override void OnError(Error error)
{
Print("Error Code {0} || {1} {2}:{3}:{4}", error.Code, Server.Time.DayOfWeek, Server.Time.Hour, Server.Time.Minute, Server.Time.Second);
}
#endregion Standard event handlers
#region Logic
private void ManagePositions()
{
/// if there is no buy position open, open one
if (IsPositionOpenByType(TradeType.Buy) == false && Extreme() == false && BuyEntry() == true && EntryBar() == true)
{
if (Trader_Bullish() == false && Investor_Bullish() == true)
{
OpenPosition(TradeType.Buy);
}
else if (Trader_Bullish() == true && Bars.ClosePrices.Last(lastbar + 1) < Bars.OpenPrices.Last(lastbar + 1))
{
OpenPosition(TradeType.Buy);
}
}
/// if there is no sell position open, open one
else if (IsPositionOpenByType(TradeType.Sell) == false && Extreme() == false && SellEntry() == true && EntryBar() == true)
{
if (Trader_Bearish() == false && Investor_Bearish() == true)
{
OpenPosition(TradeType.Sell);
}
else if (Trader_Bearish() == true && Bars.ClosePrices.Last(lastbar + 1) > Bars.OpenPrices.Last(lastbar + 1))
{
OpenPosition(TradeType.Sell);
}
}
/// Call custom class method to Close Open Position
if (IsPositionOpenByType(TradeType.Buy) == true && BuyExit() == true)
ClosePosition(TradeType.Buy);
else if (IsPositionOpenByType(TradeType.Sell) == true && SellExit() == true)
ClosePosition(TradeType.Sell);
}
#endregion Logic
#region Scale Out
private void CloseHalf()
{
var positions = Positions.FindAll(InstanceName.ToString(), SymbolName);
foreach (var position in positions)
{
var Secured = position.TradeType == TradeType.Buy ? position.StopLoss - position.EntryPrice : position.EntryPrice - position.StopLoss;
var HalfVol = Math.Round(Symbol.NormalizeVolumeInUnits(((position.VolumeInUnits) / 2), RoundingMode.ToNearest), 0);
if (ScaleOut == true && position.VolumeInUnits >= 2000 && (Secured / Symbol.PipSize) <= AddPips && position.Pips >= (ATR.Result.Last(lastbar) * ATRTakeProfit) / Symbol.PipSize)
{
ClosePosition(position, HalfVol);
Print("[ {0} ] Scale Out {1} || New Volume: {2} || Gain/Loss {3} Pips / $ {4} || {5} {6}:{7}:{8}", LastResult.Position.Id, SymbolName, position.VolumeInUnits, LastResult.Position.Pips, LastResult.Position.NetProfit, Server.Time.DayOfWeek, Server.Time.Hour, Server.Time.Minute, Server.Time.Second);
}
}
}
#endregion Scale Out
#region BreakEven
/// Call custom class method to move StopLoss to BreakEven
private void MoveToBreakEven()
{
var positions = Positions.FindAll(InstanceName.ToString(), SymbolName);
foreach (var position in positions)
{
var desiredNetProfitInDepositAsset = AddPips * Symbol.PipValue * position.VolumeInUnits;
var desiredGrossProfitInDepositAsset = desiredNetProfitInDepositAsset - position.Commissions * 2 - position.Swap;
var quoteToDepositRate = Symbol.PipValue / Symbol.PipSize;
var priceDifference = desiredGrossProfitInDepositAsset / (position.VolumeInUnits * quoteToDepositRate);
var priceAdjustment = GetPriceAdjustmentByTradeType(position.TradeType, priceDifference);
var breakEvenLevel = position.EntryPrice + priceAdjustment;
var roundedBreakEvenLevel = RoundPrice(breakEvenLevel, position.TradeType);
var stopposition = position.TradeType == TradeType.Buy ? position.EntryPrice - position.StopLoss : position.StopLoss - position.EntryPrice;
if (BreakEven == true && stopposition > 0 && position.Pips >= (ATR.Result.Last(lastbar) * TriggerPips) / Symbol.PipSize)
{
ModifyPosition(position, roundedBreakEvenLevel, position.TakeProfit);
Print("[ {0} ] Breakeven {1} || {2} {3}:{4}:{5}", LastResult.Position.Id, SymbolName, Server.Time.DayOfWeek, Server.Time.Hour, Server.Time.Minute, Server.Time.Second);
}
}
}
#endregion BreakEven
#region TrailingStop
private void SetTrailingStop()
{
var sellPositions = Positions.FindAll(InstanceName, SymbolName, TradeType.Sell);
foreach (Position position in sellPositions)
{
double distance = position.EntryPrice - Symbol.Ask;
if (distance < (ATR.Result.Last(lastbar) * TrailingStopTrigger))
continue;
double newStopLossPrice = Symbol.Ask + (ATR.Result.Last(lastbar) * TrailingStopStep);
var newStopLoss = RoundPrice(newStopLossPrice, position.TradeType);
if (UseTrailingStop == true && (position.StopLoss == null || newStopLossPrice < position.StopLoss))
ModifyPosition(position, newStopLoss, position.TakeProfit);
if (LastResult.IsSuccessful)
Print("[ {0} ] Trailing {1} || New StopLoss: {2} || {3} {4}:{5}:{6}", LastResult.Position.Id, SymbolName, LastResult.Position.StopLoss, Server.Time.DayOfWeek, Server.Time.Hour, Server.Time.Minute, Server.Time.Second);
}
var buyPositions = Positions.FindAll(InstanceName, SymbolName, TradeType.Buy);
foreach (Position position in buyPositions)
{
double distance = Symbol.Bid - position.EntryPrice;
if (distance < (ATR.Result.Last(lastbar) * TrailingStopTrigger))
continue;
double newStopLossPrice = Symbol.Bid - (ATR.Result.Last(lastbar) * TrailingStopStep);
var newStopLoss = RoundPrice(newStopLossPrice, position.TradeType);
if (UseTrailingStop == true && (position.StopLoss == null || newStopLossPrice > position.StopLoss))
ModifyPosition(position, newStopLoss, position.TakeProfit);
if (LastResult.IsSuccessful)
Print("[ {0} ] Trailing {1} || New StopLoss: {2} || {3} {4}:{5}:{6}", LastResult.Position.Id, SymbolName, LastResult.Position.StopLoss, Server.Time.DayOfWeek, Server.Time.Hour, Server.Time.Minute, Server.Time.Second);
}
}
#endregion TrailingStop
#region Open Trade
/// Call custom class method to send a market order || open a new position
private void OpenPosition(TradeType type)
{
var Pos = Positions.FindAll(InstanceName.ToString(), SymbolName);
if (Pos.Count() == 0 && Server.Time.DayOfWeek <= DayOfWeek.Friday && Server.Time.Hour <= 19 && SPREAD <= MaxSpread)
{
if (ScaleOut)
ExecuteMarketRangeOrder(type, this.Symbol.Name, volume, Slippage, Symbol.Bid, InstanceName.ToString(), StopLoss, 0, Comment);
else
ExecuteMarketRangeOrder(type, this.Symbol.Name, volume, Slippage, Symbol.Bid, InstanceName.ToString(), StopLoss, TakeProfit, Comment);
if (LastResult.IsSuccessful)
Print("[ {0} ] Open {1} {2} || Volume:{3} || Spread:{4} || {5} {6}:{7}:{8}", LastResult.Position.Id, type, SymbolName, LastResult.Position.VolumeInUnits, SPREAD, Server.Time.DayOfWeek, Server.Time.Hour, Server.Time.Minute, Server.Time.Second);
}
}
#endregion Open Trade
#region Close Trade
/// Standard event handler that triggers upon position closing.
private void ClosePosition(TradeType type)
{
var p = Positions.Find(InstanceName.ToString(), SymbolName, type);
if (p != null)
{
ClosePosition(p);
Print("[ {0} ] Close {1} {2} || Volume:{3} || Spread:{4} || Gain/Loss {5}Pips / $ {6} || {7} {8}:{9}:{10}", LastResult.Position.Id, type, SymbolName, LastResult.Position.VolumeInUnits, SPREAD, LastResult.Position.Pips, LastResult.Position.NetProfit, Server.Time.DayOfWeek, Server.Time.Hour,
Server.Time.Minute, Server.Time.Second);
}
else if (CloseOnWeekend == true && p != null && Server.Time.DayOfWeek == DayOfWeek.Friday && Server.Time.Hour >= 21 && Server.Time.Minute >= 30)
{
ClosePosition(p);
Print("[ {0} ] Close {1} on Weekend || Gain/Loss {1}Pips / $ {2} || {3} {4}:{5}:{6}", LastResult.Position.Id, SymbolName, LastResult.Position.Pips, LastResult.Position.NetProfit, Server.Time.DayOfWeek, Server.Time.Hour, Server.Time.Minute, Server.Time.Second);
}
}
/// Check for opened position
private bool IsPositionOpenByType(TradeType type)
{
var p = Positions.FindAll(InstanceName.ToString(), SymbolName, type);
if (p.Count() > 0 || p.Count() != 0)
return true;
return false;
}
private void OnPositionsClosed(PositionClosedEventArgs args)
{
// check if the position has been closed due to stoploss or takeprofit or any other(stop out etc)
if (args.Reason == PositionCloseReason.StopLoss)
{
Print("[ {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("[ {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);
}
}
#endregion Close Trade
#region Check for Setups
//////////////////////////////////////////////////////////////////////////
///////////////////////// Check for Setups //////////////////////////////
////////////////////////////////////////////////////////////////////////
private bool Trader_Bullish()
{
if (EMA_1.Result.Last(lastbar) >= EMA_2.Result.Last(lastbar) && EMA_2.Result.Last(lastbar) >= EMA_3.Result.Last(lastbar) && EMA_3.Result.Last(lastbar) >= EMA_4.Result.Last(lastbar) && EMA_4.Result.Last(lastbar) >= EMA_5.Result.Last(lastbar))
return true;
return false;
}
private bool Trader_Bearish()
{
if (EMA_1.Result.Last(lastbar) <= EMA_2.Result.Last(lastbar) && EMA_2.Result.Last(lastbar) <= EMA_3.Result.Last(lastbar) && EMA_3.Result.Last(lastbar) <= EMA_4.Result.Last(lastbar) && EMA_4.Result.Last(lastbar) <= EMA_5.Result.Last(lastbar))
return true;
return false;
}
private bool Investor_Bullish()
{
if (EMA_6.Result.Last(lastbar) >= EMA_7.Result.Last(lastbar) && EMA_7.Result.Last(lastbar) >= EMA_8.Result.Last(lastbar) && EMA_8.Result.Last(lastbar) >= EMA_9.Result.Last(lastbar) && EMA_9.Result.Last(lastbar) >= EMA_10.Result.Last(lastbar))
return true;
return false;
}
private bool Investor_Bearish()
{
if (EMA_6.Result.Last(lastbar) <= EMA_7.Result.Last(lastbar) && EMA_7.Result.Last(lastbar) <= EMA_8.Result.Last(lastbar) && EMA_8.Result.Last(lastbar) <= EMA_9.Result.Last(lastbar) && EMA_9.Result.Last(lastbar) <= EMA_10.Result.Last(lastbar))
return true;
return false;
}
private bool BuyEntry()
{
if (Bars.ClosePrices.Last(lastbar) > Bars.OpenPrices.Last(lastbar) && Bars.LowPrices.Last(lastbar) < EMA_3.Result.Last(lastbar) && Bars.ClosePrices.Last(lastbar) > EMA_1.Result.Last(lastbar) && Bars.ClosePrices.Last(lastbar) > EMA_5.Result.Last(lastbar) && Bars.ClosePrices.Last(lastbar) > EMA_6.Result.Last(lastbar) && Bars.ClosePrices.Last(lastbar) > EMA_10.Result.Last(lastbar))
return true;
return false;
}
private bool SellEntry()
{
if (Bars.ClosePrices.Last(lastbar) < Bars.OpenPrices.Last(lastbar) && Bars.HighPrices.Last(lastbar) > EMA_3.Result.Last(lastbar) && Bars.ClosePrices.Last(lastbar) < EMA_1.Result.Last(lastbar) && Bars.ClosePrices.Last(lastbar) < EMA_5.Result.Last(lastbar) && Bars.ClosePrices.Last(lastbar) < EMA_6.Result.Last(lastbar) && Bars.ClosePrices.Last(lastbar) < EMA_10.Result.Last(lastbar))
return true;
return false;
}
private bool BuyExit()
{
if (IsPositionOpenByType(TradeType.Buy) == true && EMA_1.Result.Last(lastbar) < EMA_2.Result.Last(lastbar) && EMA_1.Result.Last(lastbar) < EMA_3.Result.Last(lastbar) && Bars.ClosePrices.Last(lastbar) < EMA_5.Result.Last(lastbar))
return true;
else if (IsPositionOpenByType(TradeType.Buy) == true && Bars.ClosePrices.Last(lastbar + 1) == Bars.LowPrices.Last(lastbar + 1) && Bars.ClosePrices.Last(lastbar + 2) == Bars.LowPrices.Last(lastbar + 2))
return true;
return false;
}
private bool SellExit()
{
if (IsPositionOpenByType(TradeType.Sell) == true && EMA_1.Result.Last(lastbar) > EMA_2.Result.Last(lastbar) && EMA_1.Result.Last(lastbar) > EMA_3.Result.Last(lastbar) && Bars.ClosePrices.Last(lastbar) > EMA_5.Result.Last(lastbar))
return true;
else if (IsPositionOpenByType(TradeType.Sell) == true && Bars.ClosePrices.Last(lastbar + 1) == Bars.HighPrices.Last(lastbar + 1) && Bars.ClosePrices.Last(lastbar + 2) == Bars.HighPrices.Last(lastbar + 2))
return true;
return false;
}
private bool Extreme()
{
if (Math.Abs(EMA_1.Result.Last(lastbar) - EMA_5.Result.Last(lastbar)) > ATR.Result.Last(lastbar) * 1.618 || Math.Abs(EMA_5.Result.Last(lastbar) - EMA_6.Result.Last(lastbar)) > ATR.Result.Last(lastbar) * 1.382 || Math.Abs(EMA_6.Result.Last(lastbar) - EMA_10.Result.Last(lastbar)) > ATR.Result.Last(lastbar) * 1.618)
return true;
return false;
}
private bool EntryBar()
{
if (Math.Abs(Bars.OpenPrices.Last(lastbar) - Bars.ClosePrices.Last(lastbar)) > Math.Abs(Bars.HighPrices.Last(lastbar) - Bars.LowPrices.Last(lastbar)) * 0.618)
return true;
return false;
}
#endregion Check for Setups
#region RoundPrice
////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////
private double RoundPrice(double price, TradeType tradeType)
{
var multiplier = Math.Pow(10, Symbol.Digits);
if (tradeType == TradeType.Buy)
return Math.Ceiling(price * multiplier) / multiplier;
return Math.Floor(price * multiplier) / multiplier;
}
private static double GetPriceAdjustmentByTradeType(TradeType tradeType, double priceDifference)
{
if (tradeType == TradeType.Buy)
return priceDifference;
return -priceDifference;
}
#endregion RoundPrice
}
}
I added some debugging stuff, next time it stopped check the cTrader logs tab, there will be an error message, copy it and post it here.
@amusleh
amusleh
01 Jun 2021, 16:18
Hi,
I think there is an issue with rounding of Stop loss and take profit levels, you have to round them to symbol digits if its in price level.
If you can't do it by yourself you can post a job request or contact one of our consultants.
@amusleh
amusleh
31 May 2021, 07:50
RE: RE:
chris07 said:
This was a commissioned work and the creator wishes the code to remain private.
The built-in indicators do not have a problem with reloading data or changing TFs. How do they accomplish that vs the custom drawing tools?
Any input is appreciated.
Hi,
The reason drawings disappear is because of not being interactive, if an indicator/cBot drew something on your chart and don't make it interactive then it will disappear if indicator/cBot reloaded.
To make the indicator drawings interactive you must have access to the code.
@amusleh
amusleh
18 Jun 2021, 20:11
Hi,
cTrader Automate API gives you two option for drawing on charts:
The first one is static and doesn't depend on your chart price and time axis, the second one is more dynamic and you can position it based on chart price and time axis.
For your case I thing you should use ChartText not chart controls.
To allow user to interact with your chart object (change font size, color,...) set its IsInteractive property to True.
First call the Chart.DrawText and save the returning ChartText object on a variable, then set its IsInteractive property to True:
Checkout the ChartText example on API references and if you need a more advanced sample check the Pattern Drawing indicator code.
@amusleh