Topics
Forum Topics not found
Replies
amusleh
07 Feb 2022, 09:26
Hi,
Not sure what do you mean by color candle, but for inside bar calculation you can use this method:
/// <summary>
/// Returns True if the index bar is an inside bar
/// </summary>
/// <param name="bars"></param>
/// <param name="index">The bar index number in a market series</param>
/// <returns>bool</returns>
private bool IsInsideBar(Bars bars, int index)
{
var currentBar = bars[index];
var previousBar = bars[index - 1];
var currentBarType = currentBar.Close > currentBar.Open ? 1 : 0;
var previousBarType = previousBar.Close > previousBar.Open ? 1 : 0;
return currentBar.High < previousBar.High && currentBar.Low > previousBar.Low && currentBarType != previousBarType;
}
@amusleh
amusleh
07 Feb 2022, 09:20
Hi,
Please try this:
using System;
using System.Linq;
using cAlgo.API;
using cAlgo.API.Indicators;
using cAlgo.API.Internals;
using cAlgo.Indicators;
namespace cAlgo.Robots
{
[Robot(TimeZone = TimeZones.UTC, AccessRights = AccessRights.FullAccess)]
public class MACDBot : Robot
{
[Parameter("Name", Group = "General", DefaultValue = "MACD Bot")]
public string _Label { get; set; }
[Parameter("MACD Long", Group = "MACD", DefaultValue = 26, MaxValue = 100, MinValue = 1)]
public int _macdlong { get; set; }
[Parameter("MACD Short", Group = "MACD", DefaultValue = 12, MaxValue = 100, MinValue = 1)]
public int _macdshort { get; set; }
[Parameter("MACD Signal", Group = "MACD", DefaultValue = 9, MaxValue = 100, MinValue = 1)]
public int _macdsig { get; set; }
[Parameter("MA Type", Group = "Moving Average", DefaultValue = MovingAverageType.Exponential)]
public MovingAverageType _matype { get; set; }
[Parameter("MA Period", Group = "Moving Average", DefaultValue = 200, MaxValue = 1000, MinValue = 1)]
public int _maperiod { get; set; }
[Parameter("Reward", Group = "Risk", DefaultValue = 1.5, MaxValue = 10.0, MinValue = 0.1, Step = 0.1)]
public double _reward { get; set; }
[Parameter("Pip Limiter", Group = "Risk", DefaultValue = 8.0, MaxValue = 50.0, MinValue = 0.1, Step = 0.1)]
public double _limiter { get; set; }
[Parameter("Position Size", Group = "Risk", DefaultValue = 1.0, MaxValue = 100.0, MinValue = 0.01, Step = 0.01)]
public double _size { get; set; }
[Parameter("Stop Loss Buffer", Group = "Risk", DefaultValue = 1.0, MaxValue = 50.0, MinValue = 0.01, Step = 0.01)]
public double _slbuffer { get; set; }
public MacdCrossOver _macd;
public MovingAverage _ma;
private bool _macdbuy, _macdsell, _maq, _distanceq;
public double _getsl, _gettp, _distance;
protected override void OnStart()
{
_macd = Indicators.MacdCrossOver(_macdlong, _macdshort, _macdsig);
_ma = Indicators.MovingAverage(Bars.ClosePrices, _maperiod, _matype);
_slbuffer = 1.0;
_distance = 0.0;
}
protected override void OnBar()
{
var _activebuy = Positions.Find(_Label, SymbolName, TradeType.Buy);
var _activesell = Positions.Find(_Label, SymbolName, TradeType.Sell);
var _volume = Symbol.QuantityToVolumeInUnits(_size);
_distance = Math.Abs((_ma.Result.LastValue - Bars.ClosePrices.LastValue) / Symbol.PipSize);
_maq = Bars.ClosePrices.Last(1) > _ma.Result.Last(1) ? true : false;
_distanceq = _distance < _limiter ? true : false;
if (_macd.MACD.HasCrossedAbove(_macd.Signal, 1) && _macd.MACD.Last(1) < 0)
{
_macdbuy = true;
}
if (_macd.MACD.HasCrossedBelow(_macd.Signal, 1) && _macd.MACD.Last(1) > 0)
{
_macdsell = true;
}
if (_activebuy == null && _maq && _distanceq && _macdbuy)
{
_getsl = GetStopLoss();
_gettp = GetTakeProfit();
if (_activesell != null)
{
ClosePosition(_activesell);
}
ExecuteMarketOrder(TradeType.Buy, Symbol.Name, _volume, _Label, _getsl, _gettp);
}
if (_activesell == null && !_maq && _distanceq && _macdsell)
{
_getsl = GetStopLoss();
_gettp = GetTakeProfit();
if (_activesell != null)
{
ClosePosition(_activesell);
}
ExecuteMarketOrder(TradeType.Sell, Symbol.Name, _volume, _Label, _getsl, _gettp);
}
}
private double GetStopLoss()
{
double _result = Math.Abs((_ma.Result.Last(1) - Bars.ClosePrices.Last(1)) / Symbol.PipSize);
_result = _result + _slbuffer;
return _result;
}
private double GetTakeProfit()
{
double result = _getsl * _reward;
return result;
}
}
}
I back tested it and it works fine:
@amusleh
amusleh
07 Feb 2022, 09:05
Hi,
Spread is the difference between a symbol Bid and Ask price levels, so to get spread you need both bid and ask price of a symbol and then you can subtract one from another and get the spread.
To get live price quotes you have to subscribe to a symbol spot event, and after that you will keep getting price quotes unless you unsubscribe from the event.
@amusleh
amusleh
07 Feb 2022, 08:56
Hi,
You can use Position Pips property to get the current Pips amount of Position, ex:
using cAlgo.API;
namespace cAlgo.Robots
{
[Robot(TimeZone = TimeZones.EasternStandardTime, AccessRights = AccessRights.FullAccess)]
public class AUDJPY : Robot
{
[Parameter("Trade Size", DefaultValue = 1000, MinValue = 0.01)]
public double Size { get; set; }
[Parameter("Stop Loss (Pips)", DefaultValue = 15, MinValue = 2)]
public int SL { get; set; }
[Parameter("Take Profit (Pips)", DefaultValue = 35, MinValue = 2)]
public int TP { get; set; }
protected override void OnStart()
{
ExecuteMarketOrder(TradeType.Buy, SymbolName, Size, SymbolName, 0, 10);
}
protected override void OnTick()
{
// It iterates over all positions
foreach (var position in Positions)
{
// if position is 5 pips in profit
if (position.Pips == 5)
{
// Do something here, ex: execute a new order
}
// if position is 5 pips in lose
else if (position.Pips == -5)
{
// Do something here, ex: execute a new order
}
}
}
}
}
@amusleh
amusleh
04 Feb 2022, 08:55
Hi,
The Chart FindObject method returns a ChartObject which is the base class of all other chart objects.
ChartObject class has no y value property, you should cast it to ChartHorizontalLine class, ex:
using cAlgo.API;
namespace cAlgo
{
[Indicator(IsOverlay = true, TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
public class NewIndicator : Indicator
{
protected override void Initialize()
{
// The line is a ChartHorizontalLine object
var line = Chart.DrawHorizontalLine("myLine", Bars.LowPrices[Chart.LastVisibleBarIndex], Color.Red);
// Now to get the line back
var myLine = Chart.FindObject("myLine") as ChartHorizontalLine;
if (myLine != null)
{
var yValue = myLine.Y;
Print(yValue);
}
}
public override void Calculate(int index)
{
}
}
}
@amusleh
amusleh
03 Feb 2022, 10:38
RE: RE:
heinrich.munz said:
When will version 4.2 be available from the brokers? Pepperstone and IC Markets still are on 4.1
Hi,
Version 4.2 is a major release with lots of changes, we move from .NET framework to .NET 6.
It will be released this year but I can't give you an exact ETA.
@amusleh
amusleh
03 Feb 2022, 08:45
Hi,
Do you mean something like this:
private bool CheckADX()
{
if (adxType == ADXType.None)
{
return true;
}
double adxLastLevel = _adx.ADX.Last(1);
double adxPreviousLevel = _adx.ADX.Last(2);
if (adxType == ADXType.Gradient)
{
// it will return true if ADX is raising and it's above 25
if (adxLastLevel > adxPreviousLevel && adxLastLevel > 25)
{
return true;
}
}
else
{
if (adxLastLevel > adxLevel)
{
return true;
}
}
return false;
}
You can add more conditions on an if statement by using && (and) or || (or),
@amusleh
amusleh
03 Feb 2022, 08:38
Hi,
Yes, it's possible, you can develop a cBot that will run on the background and whenever you execute an order it can set SL/TP based on your written logic.
You can also use Chart controls to build something more interactive with buttons and other type of controls.
@amusleh
amusleh
02 Feb 2022, 08:35
RE: RE: RE: RE: RE:
SummerSalt said:
Hello,
I have now tested the code you provided and it works well, thank you very much. I was not able to test it earlier because I did not work set the position.count to > 2 (my bot executes 2 orders at once), which made me think I had to call your code using the OnTick() function for it to work. However, I am still having the problem of the levels not closing at the exact specified pip amount (like with StopLoss or Take Profit). Is there a way of improving the accuracy at which the pips close?
Thanks for your patience so far.
Hi,
What do you mean by levels not closing at the exact specified pip amount?
The bot closes a portion of your position when its Pips reach your set amount.
@amusleh
amusleh
02 Feb 2022, 08:33
Hi,
There are different ways to select bars, one is by mouse click event that you can use when user click on one bar and then on another bar, you can get the mouse click bar index.
You can also use Rectangle which is much better way than using mouse click event, use Chart object events like chart object added, check the rectangle Time1 and Time2 properties and change it to bar index.
Here is an example with rectangle:
using cAlgo.API;
using System.Linq;
namespace cAlgo
{
[Indicator(IsOverlay = true, TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
public class CandlesSelectionWithRectangle : Indicator
{
protected override void Initialize()
{
Chart.ObjectsAdded += Chart_ObjectsAdded;
}
private void Chart_ObjectsAdded(ChartObjectsAddedEventArgs obj)
{
var chartRectangleObject = obj.ChartObjects.FirstOrDefault(chartObject => chartObject.ObjectType == ChartObjectType.Rectangle);
if (chartRectangleObject == null) return;
var rectangle = chartRectangleObject as ChartRectangle;
var startTime = rectangle.Time1 < rectangle.Time2 ? rectangle.Time1 : rectangle.Time2;
var endTime = rectangle.Time1 < rectangle.Time2 ? rectangle.Time2 : rectangle.Time1;
var startBarIndex = Bars.OpenTimes.GetIndexByTime(startTime);
var endBarIndex = Bars.OpenTimes.GetIndexByTime(endTime);
Print("startBarIndex: {0} | endBarIndex: {1}", startBarIndex, endBarIndex);
for (int barIndex = startBarIndex; barIndex <= endBarIndex; barIndex++)
{
var bar = Bars[barIndex];
// do anythign you want to with the bars here
}
}
public override void Calculate(int index)
{
}
}
}
Create an instance of indicator on cTrader automate, draw a rectangle on your chart, check the logs tab.
@amusleh
amusleh
02 Feb 2022, 08:22
RE: I could not install!!!
meeting.chegini said:
Attempting to gather dependency information for package 'cAlgo.API.Alert.2.2.2' with respect to project 'New cBot (2)', targeting '.NETFramework,Version=v4.5'
Attempting to resolve dependencies for package 'cAlgo.API.Alert.2.2.2' with DependencyBehavior 'Lowest'
Resolving actions to install package 'cAlgo.API.Alert.2.2.2'
Resolved actions to install package 'cAlgo.API.Alert.2.2.2'
Adding package 'CommonServiceLocator.2.0.4' to folder 'C:\Users\parsin\Documents\cAlgo\Sources\Robots\New cBot (2)\packages'
Added package 'CommonServiceLocator.2.0.4' to folder 'C:\Users\parsin\Documents\cAlgo\Sources\Robots\New cBot (2)\packages'
Added package 'CommonServiceLocator.2.0.4' to 'packages.config'
Successfully installed 'CommonServiceLocator 2.0.4' to New cBot (2)
Adding package 'ControlzEx.3.0.2.4' to folder 'C:\Users\parsin\Documents\cAlgo\Sources\Robots\New cBot (2)\packages'
Added package 'ControlzEx.3.0.2.4' to folder 'C:\Users\parsin\Documents\cAlgo\Sources\Robots\New cBot (2)\packages'
Added package 'ControlzEx.3.0.2.4' to 'packages.config'
Successfully installed 'ControlzEx 3.0.2.4' to New cBot (2)
Adding package 'LiteDB.5.0.9' to folder 'C:\Users\parsin\Documents\cAlgo\Sources\Robots\New cBot (2)\packages'
Added package 'LiteDB.5.0.9' to folder 'C:\Users\parsin\Documents\cAlgo\Sources\Robots\New cBot (2)\packages'
Install failed. Rolling back...
Package 'LiteDB.5.0.9' does not exist in project 'New cBot (2)'
Removed package 'ControlzEx.3.0.2.4' from 'packages.config'
Removed package 'CommonServiceLocator.2.0.4' from 'packages.config'
Removing package 'LiteDB.5.0.9' from folder 'C:\Users\parsin\Documents\cAlgo\Sources\Robots\New cBot (2)\packages'
Removed package 'LiteDB.5.0.9' from folder 'C:\Users\parsin\Documents\cAlgo\Sources\Robots\New cBot (2)\packages'
Removing package 'ControlzEx.3.0.2.4' from folder 'C:\Users\parsin\Documents\cAlgo\Sources\Robots\New cBot (2)\packages'
Removed package 'ControlzEx.3.0.2.4' from folder 'C:\Users\parsin\Documents\cAlgo\Sources\Robots\New cBot (2)\packages'
Removing package 'CommonServiceLocator.2.0.4' from folder 'C:\Users\parsin\Documents\cAlgo\Sources\Robots\New cBot (2)\packages'
Removed package 'CommonServiceLocator.2.0.4' from folder 'C:\Users\parsin\Documents\cAlgo\Sources\Robots\New cBot (2)\packages'
Failed to add reference to 'System.Runtime'. Please make sure that it is in the Global Assembly Cache.
========== Finished ==========
please guide me!
Hi.
Do you have .NET framework 4.5 on your system? if you don't install it and then retry.
@amusleh
amusleh
01 Feb 2022, 15:38
RE: RE: RE: RE:
ncel01 said:
amusleh,
That's the only purpose in fact.
Should I provide different names to the main class ( public class cBot_copy_n : Robot) for each cBot copy or, is this not relevant?
Thank you!
Hi,
It doesn't makes any difference if you use same class name or different class names.
@amusleh
amusleh
01 Feb 2022, 12:38
RE: RE:
ncel01 said:
Hi amusleh,
Thanks for your reply.
The benefit was to have the instances separated in groups, where each group is a cBot copy.
What would be the main issue here? Performance?
Is the strategy outcome/behaviour expected to be the same for both these cases?
Thank you!
Hi,
If you want to duplicate a cBot for grouping then yes you can and it will not have any effect on it's performance.
@amusleh
amusleh
01 Feb 2022, 08:46
Hi,
To use Open API you need an API application, there is no relation between an API application and cTrader trading accounts.
You can use an API application to access as many cTrader trading accounts you want to from different or same cTrader IDs.
Now, the first thing you do after opening a connection with Open API endpoints is to authorize an API application, for each connection you can only use one API application.
The authorization of your API application will tell the API server that your connection will use that application for it's life time, you can't send any other request to API server unless you first authorize an API application, to authorize your app you have to send a ProtoOAApplicationAuthReq, and once you received back a ProtoOAApplicationAuthRes it means your app is authorized and you can start interacting with API.
That was the first step, and as I said before there is no relation between a trading account and an API application.
After API application authentication you can start getting cTrader trading accounts data or execute trade operations on them, to do that you need an access token, the token will be given to your API application if a user authorized your app to access his cTrader trading accounts, for that check the documentation account authentication page.
After you got the token, you can start to use those authorized trading accounts, the first step is to send an account authentication request with account ID and access token,
You can send account auth request to any number of accounts, there is no limit, but your connection environment must match with account type, if your connected to live endpoint then you can only work with live accounts and if you are connected to demo endpoint then you can only work with demo accounts.
Once you received account auth response then you can start sending other requests related to that account, like getting account data or executing trades.
Now, regarding events:
- ProtoOAAccountDisconnectEvent: It happens if your session with a trading account ends, the session starts when you send an account auth request, and if it happened you have to re-send a new account auth request
- ProtoOAClientDisconnectEvent: It happens if the server cancels all your sessions with your authorized trading accounts, in that case you should reconnect and re authorize all trading accounts by sending account auth request, and before that you also have to send app auth request
- ProtoOAAccountsTokenInvalidatedEvent: This happens if you authorized to use a trading account, and you have an active session, and the access token is invalidated either by it's expiry time or user revoking access to your app, in such a case you should try to refresh the access token and establish a new session by sending a new account auth request
Hopefully now it's much more clear for you.
If you had any other question let me know.
@amusleh
amusleh
01 Feb 2022, 08:02
Hi,
To use a custom indicator on your cBot you have to use the Indicators.GetIndicator generic method: Method GetIndicator | API reference | cTrader Community
But your indicator uses some native Win32 API for showing a message box, you have to remove it:
using System;
using cAlgo.API;
using cAlgo.API.Indicators;
namespace cAlgo.Indicators
{
[Indicator(IsOverlay = true, TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
public class SuperProfit : Indicator
{
[Parameter(DefaultValue = 35)]
public int DllPeriod { get; set; }
[Parameter(DefaultValue = 1.7)]
public double Period { get; set; }
[Parameter(DefaultValue = MovingAverageType.Weighted)]
public MovingAverageType MaType { get; set; }
[Parameter()]
public DataSeries Price { get; set; }
[Parameter(DefaultValue = 5)]
public int StopLoss { get; set; }
[Parameter(DefaultValue = 20)]
public int TakeProfit { get; set; }
[Output("Up", PlotType = PlotType.Points, Thickness = 4)]
public IndicatorDataSeries UpSeries { get; set; }
[Output("Down", PlotType = PlotType.Points, Color = Colors.Red, Thickness = 4)]
public IndicatorDataSeries DownSeries { get; set; }
private DateTime _openTime;
private MovingAverage _movingAverage1;
private MovingAverage _movingAverage2;
private MovingAverage _movingAverage3;
private IndicatorDataSeries _dataSeries;
private IndicatorDataSeries _trend;
protected override void Initialize()
{
_dataSeries = CreateDataSeries();
_trend = CreateDataSeries();
var period1 = (int)Math.Floor(DllPeriod / Period);
var period2 = (int)Math.Floor(Math.Sqrt(DllPeriod));
_movingAverage1 = Indicators.MovingAverage(Price, period1, MaType);
_movingAverage2 = Indicators.MovingAverage(Price, DllPeriod, MaType);
_movingAverage3 = Indicators.MovingAverage(_dataSeries, period2, MaType);
}
public override void Calculate(int index)
{
if (index < 1)
return;
_dataSeries[index] = 2.0 * _movingAverage1.Result[index] - _movingAverage2.Result[index];
_trend[index] = _trend[index - 1];
if (_movingAverage3.Result[index] > _movingAverage3.Result[index - 1])
_trend[index] = 1;
else if (_movingAverage3.Result[index] < _movingAverage3.Result[index - 1])
_trend[index] = -1;
if (_trend[index] > 0)
{
UpSeries[index] = _movingAverage3.Result[index];
if (_trend[index - 1] < 0.0)
{
UpSeries[index - 1] = _movingAverage3.Result[index - 1];
if (IsLastBar)
{
var stopLoss = MarketSeries.Low[index - 1] - StopLoss * Symbol.PipSize;
var takeProfit = MarketSeries.Close[index] + TakeProfit * Symbol.PipSize;
var entryPrice = MarketSeries.Close[index - 1];
if (MarketSeries.OpenTime[index] != _openTime)
{
_openTime = MarketSeries.OpenTime[index];
}
}
}
DownSeries[index] = double.NaN;
}
else if (_trend[index] < 0)
{
DownSeries[index] = _movingAverage3.Result[index];
if (_trend[index - 1] > 0.0)
{
DownSeries[index - 1] = _movingAverage3.Result[index - 1];
if (IsLastBar)
{
var stopLoss = MarketSeries.High[index - 1] + StopLoss * Symbol.PipSize;
var takeProfit = MarketSeries.Close[index] - TakeProfit * Symbol.PipSize;
var entryPrice = MarketSeries.Close[index - 1];
if (MarketSeries.OpenTime[index] != _openTime)
{
_openTime = MarketSeries.OpenTime[index];
}
}
}
UpSeries[index] = double.NaN;
}
}
}
}
Then right click on your cBot, select reference manager, and inside indicators tab fine the "SuperProfit", reference it by checking its checkbox and then click on Ok button.
After referencing the indicator, rebuild your cBot, then you will be able to use the indicator inside your cBot, ex:
using cAlgo.API;
using cAlgo.API.Internals;
using cAlgo.Indicators;
namespace cAlgo.Robots
{
[Robot(TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
public class sajad : Robot
{
private double _volumeInUnits;
private SuperProfit _superProfit;
[Parameter("Volume (Lots)", DefaultValue = 0.05)]
public double VolumeInLots { get; set; }
[Parameter("Stop Loss (Pips)", DefaultValue = 100)]
public double StopLossInPips { get; set; }
[Parameter("Take Profit (Pips)", DefaultValue = 100)]
public double TakeProfitInPips { get; set; }
[Parameter("Label", DefaultValue = "superprofit")]
public string Label { get; set; }
public Position[] BotPositions
{
get { return Positions.FindAll(Label); }
}
protected override void OnStart()
{
// You have to pass each indicator parameter value in order
// I used the default values but you can change them if you want to
// Or use cBot parameters and then use their values
_superProfit = Indicators.GetIndicator<SuperProfit>(35, 1.7, MovingAverageType.Weighted, Bars.ClosePrices, 5, 20);
_volumeInUnits = Symbol.QuantityToVolumeInUnits(VolumeInLots);
}
protected override void OnBar()
{
if (_superProfit.UpSeries.LastValue == double.NaN)
{
ClosePositions(TradeType.Sell);
ExecuteMarketOrder(TradeType.Buy, SymbolName, _volumeInUnits, Label, StopLossInPips, TakeProfitInPips);
}
else if (_superProfit.DownSeries.LastValue == double.NaN)
{
ClosePositions(TradeType.Buy);
ExecuteMarketOrder(TradeType.Sell, SymbolName, _volumeInUnits, Label, StopLossInPips, TakeProfitInPips);
}
}
private void ClosePositions(TradeType tradeType)
{
foreach (var position in BotPositions)
{
if (position.TradeType != tradeType)
continue;
ClosePosition(position);
}
}
}
}
And next time you post code please use the editor "Insert code snippet" option like I did.
@amusleh
amusleh
07 Feb 2022, 09:28
Hi,
Can't you zoom out? switch to a larger time frame?
If you want to automatically mark some kind of pattern or support and resistance levels then you can develop an indicator for that based on your own calculation logic/formula.
@amusleh