Topics
Forum Topics not found
Replies
amusleh
20 Apr 2022, 09:23
Hi,
Try this:
using System;
using cAlgo.API;
using cAlgo.API.Internals;
namespace cAlgo
{
[Indicator(IsOverlay = true, TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
public class USDCorelation : Indicator
{
[Parameter("Reset Time", DefaultValue = "2022-4-19 22:15:00", Group = "Ver. 1.01")]
public string ResetPoint { get; set; }
[Output("GBP", LineColor = "FFB600FF", Thickness = 2, PlotType = PlotType.DiscontinuousLine)]
public IndicatorDataSeries GBP { get; set; }
[Output("NZD", LineColor = "FF00BF00", Thickness = 2, PlotType = PlotType.DiscontinuousLine)]
public IndicatorDataSeries NZD { get; set; }
private DateTime dt_RstPnt; //Reset Time Point;
//Bars to load for Calculate
private Bars EURUSD, GBPUSD, NZDUSD;
//Index at ResetTimePoint of EachSymbol;
private int in_EURUSD, in_GBPUSD, in_NZDUSD;
//BaseValue at ResetTimePoint of EachSymbol;
private double db_EURUSD, db_GBPUSD, db_NZDUSD;
protected override void Initialize()
{
//1.Get MarketData in Series Ready
EURUSD = MarketData.GetBars(Bars.TimeFrame, "EURUSD");
GBPUSD = MarketData.GetBars(Bars.TimeFrame, "GBPUSD");
NZDUSD = MarketData.GetBars(Bars.TimeFrame, "NZDUSD");
//2.Get ResetTimePoint Index
dt_RstPnt = DateTime.Parse(ResetPoint).Add(-Application.UserTimeOffset);
in_EURUSD = EURUSD.OpenTimes.GetIndexByTime(dt_RstPnt);
in_GBPUSD = GBPUSD.OpenTimes.GetIndexByTime(dt_RstPnt);
in_NZDUSD = NZDUSD.OpenTimes.GetIndexByTime(dt_RstPnt);
//3.Get OpenPrice of each symbol at ResetTimePoint
db_EURUSD = EURUSD[in_EURUSD].Open;
db_GBPUSD = GBPUSD[in_GBPUSD].Open;
db_NZDUSD = NZDUSD[in_NZDUSD].Open;
}
public override void Calculate(int index)
{
if (Bars.OpenTimes[index] < dt_RstPnt) return;
var gbpIndex = GBPUSD.OpenTimes.GetIndexByTime(Bars.OpenTimes[index]);
var gbpGap = gbpIndex - in_GBPUSD;
GBP[index] = ((GBPUSD[in_GBPUSD + gbpGap].Close) + db_EURUSD - db_GBPUSD);
var nzdIndex = NZDUSD.OpenTimes.GetIndexByTime(Bars.OpenTimes[index]);
var nzdGap = nzdIndex - in_NZDUSD;
NZD[index] = ((NZDUSD[in_NZDUSD + nzdGap].Close) + db_EURUSD - db_NZDUSD);
}
}
}
@amusleh
amusleh
20 Apr 2022, 09:10
Hi,
You can use the TriggerAlert method instead of ShowPopup:
using cAlgo.API;
using cAlgo.API.Indicators;
using cAlgo.API.Alert;
namespace cAlgo
{
[Indicator(IsOverlay = false, TimeZone = TimeZones.UTC, AccessRights = AccessRights.FullAccess)]
public class ADXwithAlert : Indicator
{
private AverageDirectionalMovementIndexRating _adx;
private int _lastAlertBarIndex;
[Parameter(DefaultValue = 14, Group = "ADX")]
public int Periods { get; set; }
[Parameter("Level", DefaultValue = 25, Group = "Alert")]
public double AlertLevel { get; set; }
[Parameter("Setup", DefaultValue = 25, Group = "Alert")]
public bool AlertSetup { get; set; }
[Output("ADX", LineColor = "Blue")]
public IndicatorDataSeries Adx { get; set; }
[Output("ADXR", LineColor = "Yellow")]
public IndicatorDataSeries AdxR { get; set; }
[Output("DI+", LineColor = "Green")]
public IndicatorDataSeries DiPlus { get; set; }
[Output("DI-", LineColor = "Red")]
public IndicatorDataSeries DiMinus { get; set; }
protected override void Initialize()
{
_adx = Indicators.AverageDirectionalMovementIndexRating(Periods);
if (AlertSetup)
{
Notifications.ShowPopup();
}
}
public override void Calculate(int index)
{
Adx[index] = _adx.ADX[index];
AdxR[index] = _adx.ADXR[index];
DiPlus[index] = _adx.DIPlus[index];
DiMinus[index] = _adx.DIMinus[index];
if (IsLastBar && _lastAlertBarIndex != index && Adx[index] > AlertLevel)
{
_lastAlertBarIndex = index;
var type = string.Format("ADX above {0}", AlertLevel);
AlertModel alert = new AlertModel
{
TimeFrame = TimeFrame,
Symbol = Symbol,
Price = Adx[index],
TriggeredBy = "ADX with Alert",
Type = type,
Time = Server.Time
};
Notifications.TriggerAlert(alert);
}
}
}
}
It only works if you already setup the telegram alert on popup settings.
@amusleh
amusleh
19 Apr 2022, 09:48
RE: RE:
ncel01 said:
amusleh said:
Hi,
Try this:
using cAlgo.API; using System.Linq; using System.Threading; namespace cAlgo.Robots { [Robot(TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)] public class NewcBot : Robot { private bool allPositionsClosed = false; protected override void OnStart() { var tradeResults = SetTrade(); Print("Closing Positions"); foreach (var tradeResult in tradeResults) { ClosePosition(tradeResult.Position); } allPositionsClosed = true; Print("All positions closed: ", allPositionsClosed); Stop(); } private TradeResult[] SetTrade() { var tradeResults = new TradeResult[3]; tradeResults[0] = ExecuteMarketOrder(TradeType.Buy, SymbolName, Symbol.QuantityToVolumeInUnits(0.01), "order_1"); tradeResults[1] = ExecuteMarketOrder(TradeType.Buy, SymbolName, Symbol.QuantityToVolumeInUnits(0.01), "order_2"); tradeResults[2] = ExecuteMarketOrder(TradeType.Buy, SymbolName, Symbol.QuantityToVolumeInUnits(0.01), "order_3"); while (tradeResults.Any(result => result.Position is null)) { Thread.Sleep(100); RefreshData(); } return tradeResults; } protected override void OnStop() { } } }
Hi amusleh,
I am afraid that creating time delays will not solve the issue as there are dozens/hundreds of orders involved and this wouldn't be an efficient/effective solution at all, I believe.Because either the Positions collection is not updated yet (in my case), it gets updated after the thread is released from the execution of an event (OnStart. OnBar, OnTick, etc...) or even if it's updated (based on your output) the close position request can't suspend the current execution and jump to executing the event handlers (here Positions_Closed).
What can be a reason for such limitation? Wouldn't be possible that these follow the code sequence, as it happens for user-defined methods?
I am sure this would be much more intuitive and, as result, the outcome a lot more effective. Looks to me that managing a high amount of orders/positions seems to be quite hard (if not impossible) considering that internal (API) methods/functions execute asynchronously with respect to the code sequence.
Is there available any diagram (or similar) illustrating how execution is processed through cTrader API functions/methods? I believe this particularity is not really a detail when it comes to creating any "reliable" (behaving as expected) cBot/strategy. Maybe I can get to a solution if I am fully aware of how this really works. So far, it looks like I've been on a loop trying to get this solved.
Does this characteristic/limitation only apply to the events or, to any method? Only to methods?
Another question: PendingOrders_Created() and PlaceStopOrderAsync(). Do these methods always get triggered simultaneously (as a pair) or, can be that some code is still executed in between?
On my last attempt, I've added PendingOrders_Created() event. The goal was only to modify the value of a variable inside the event. However, soon I noticed that, unlike for a single order, the amount of orders keeps increasing whenever the "real" order is placed. A "clone" order is created, which does not happen if only a single order is initially defined. I also don't know why this is happening nor I do know how to solve this.
My strategy has 2000+ code lines and it is almost finished (I would say). So far, I've been able to solve every issue I noticed but not this one. The only issue, still remaining, is in fact, related to the loop ( pending order placed --> pending order filled --> position closed --> pending order placed ... ), which is still not working as expected, after many tries.
Thank you once again!
Hi,
There is no way to prevent waiting, Automate API is an abstraction over sending and receiving messages to cTrader server, if you have done any kind of network programming you know that when you send something to server/client you have to wait to get back a response, when you send a request from Automate API you have to wait to get back the response from server, there we use the Thread.Sleep method to wait until we receive response for all of our order requests from server.
Regarding your other points, all operations on a cBot is executed by a single thread, and a single thread can execute a single line of code at the time.
If you understand how a single thread environment works you will be able to understand how cTrader automate executes your code.
cTrader automate executes your cBot overloaded methods and event handlers one by one, if the thread is inside OnTick method and a position is closed it can't suspend OnTick method execution and jump to your Position closed event handler, first it finish the execution of OnTick method then it executes your position closed event handler, the same is true for all other methods, event handlers, and collections (Positions and PendingOrders).
When you send something to server you have to wait to get back the response, you can't expect the response to be available instantly, if you sent a market order request you can't expect Positions collections to have your market order position immediately.
A better approach for you to control the sequence of execution will be used the Async calls with callbacks, the async method callbacks will be called when a response is received from server, and while waiting for server response you can execute some other code instead of suspending the thread and waiting for a server response.
@amusleh
amusleh
18 Apr 2022, 18:48
Hi,
We are working on a cross platform console app that will allow you to run cBots on both Linux and Mac.
Regarding other Automate features like custom indicators you can only use them on a cTrader desktop which will not be available for Mac or Linux because it uses WPF.
@amusleh
amusleh
18 Apr 2022, 10:39
Hi,
Try this:
using cAlgo.API;
using System.Linq;
using System.Threading;
namespace cAlgo.Robots
{
[Robot(TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
public class NewcBot : Robot
{
private bool allPositionsClosed = false;
protected override void OnStart()
{
var tradeResults = SetTrade();
Print("Closing Positions");
foreach (var tradeResult in tradeResults)
{
ClosePosition(tradeResult.Position);
}
allPositionsClosed = true;
Print("All positions closed: ", allPositionsClosed);
Stop();
}
private TradeResult[] SetTrade()
{
var tradeResults = new TradeResult[3];
tradeResults[0] = ExecuteMarketOrder(TradeType.Buy, SymbolName, Symbol.QuantityToVolumeInUnits(0.01), "order_1");
tradeResults[1] = ExecuteMarketOrder(TradeType.Buy, SymbolName, Symbol.QuantityToVolumeInUnits(0.01), "order_2");
tradeResults[2] = ExecuteMarketOrder(TradeType.Buy, SymbolName, Symbol.QuantityToVolumeInUnits(0.01), "order_3");
while (tradeResults.Any(result => result.Position is null))
{
Thread.Sleep(100);
RefreshData();
}
return tradeResults;
}
protected override void OnStop()
{
}
}
}
@amusleh
amusleh
18 Apr 2022, 10:23
Hi,
Please create a job request or contact one of the consultant companies.
@amusleh
amusleh
18 Apr 2022, 10:18
Hi,
Do you mean the current bar index?
To access current bar index of another time frame Bars you can use Bars.OpenTimes.GetIndexByTime method: cAlgo API Reference - TimeSeries Interface (ctrader.com)
@amusleh
amusleh
18 Apr 2022, 10:16
Hi,
If you changed the target of your indicator and then recompiled/rebuild an indicator inside cTrader 4.2 then it's project structure changed, if you compile it again on cTrader 4.1 you will get that Guid error.
To solve this issue you can recreate those indicators inside cTrader 4.1 and just copy the code from old ones to new ones.
cTrader 4.2 is backward compatible, but cTrader 4.1 can't use cTrader 4.2 indicators/cBots.
@amusleh
amusleh
18 Apr 2022, 10:03
Hi,
You sent use the source code file of Sample EMA indicator, I tested both version 4.1 and 4.2, it works fine.
I referenced it by another indicator and it worked, then I used it on version 4.2 and it worked without any issue.
I was not able to replicate the issue you are facing.
I asked you to send us the indicator ".algo" file with it's solution directory, zip them and then send them.
Regarding the exceptions you are facing, please submit a troubleshoot report with the forum thread link.
@amusleh
amusleh
15 Apr 2022, 13:09
Hi,
You can use this:
using cAlgo.API;
using cAlgo.API.Indicators;
using cAlgo.API.Alert;
namespace cAlgo
{
[Indicator(IsOverlay = false, TimeZone = TimeZones.UTC, AccessRights = AccessRights.FullAccess)]
public class ADXwithAlert : Indicator
{
private AverageDirectionalMovementIndexRating _adx;
private int _lastAlertBarIndex;
[Parameter(DefaultValue = 14, Group = "ADX")]
public int Periods { get; set; }
[Parameter("Level", DefaultValue = 25, Group = "Alert")]
public double AlertLevel { get; set; }
[Parameter("Setup", DefaultValue = 25, Group = "Alert")]
public bool AlertSetup { get; set; }
[Output("ADX", LineColor = "Blue")]
public IndicatorDataSeries Adx { get; set; }
[Output("ADXR", LineColor = "Yellow")]
public IndicatorDataSeries AdxR { get; set; }
[Output("DI+", LineColor = "Green")]
public IndicatorDataSeries DiPlus { get; set; }
[Output("DI-", LineColor = "Red")]
public IndicatorDataSeries DiMinus { get; set; }
protected override void Initialize()
{
_adx = Indicators.AverageDirectionalMovementIndexRating(Periods);
if (AlertSetup)
{
Notifications.ShowPopup();
}
}
public override void Calculate(int index)
{
Adx[index] = _adx.ADX[index];
AdxR[index] = _adx.ADXR[index];
DiPlus[index] = _adx.DIPlus[index];
DiMinus[index] = _adx.DIMinus[index];
if (IsLastBar && _lastAlertBarIndex != index && Adx[index] > AlertLevel)
{
_lastAlertBarIndex = index;
var type = string.Format("ADX above {0}", AlertLevel);
Notifications.ShowPopup(TimeFrame, Symbol, type, "ADX with Alert");
}
}
}
}
It uses the cAlgo.API.Alert Nuget package.
To use it:
- Copy the code on a new indicator and save
- Open indicator in Visual studio
- Change the Project .NET framework to target 4.5
- Install cAlgo.API.Alert Nuget package
- Rebuild the indicator from Visual Studio
For a more detailed guide check: Installation · afhacker/ctrader-alert_popup Wiki (github.com)
For Telegram notification setup check: Telegram · afhacker/ctrader-alert_popup Wiki (github.com)
@amusleh
amusleh
15 Apr 2022, 08:57
Hi,
cTrader cBots/Indicators run on a single thread and their code indeed are executed sequentially.
Regarding your code, this is the result I got:
15/04/2022 13:10:42.947 | CBot instance [New cBot, EURUSD, h1] started.
15/04/2022 13:10:43.650 | Stage #1
15/04/2022 13:10:44.134 | Stage #2
15/04/2022 13:10:44.556 | Stage #5
15/04/2022 13:10:44.556 | Stage #4
15/04/2022 13:10:44.588 | CBot instance [New cBot, EURUSD, h1] stopped.
The Stage #1 gets printed because it's the first line to be executed inside SetTrade method, all good for now.
The Stage #2 is printed as it's the next line after Stack execution pointer returns from SetMethod.
Next is the loop for closing positions, it iterates over Positions collection and then sends a Close request for each of the positions, then why "Stage #3" is not printed?
Because either the Positions collection is not updated yet (in my case), it gets updated after the thread is released from the execution of an event (OnStart. OnBar, OnTick, etc...) or even if it's updated (based on your output) the close position request can't suspend the current execution and jump to executing the event handlers (here Positions_Closed).
It waits for thread to become free and then it executes the event handler of Positions.Closed event, that's what happened on your case.
Same thing is happening for Stop call, when you call the Stop method it can't suspend the execution of OnStart method and jump to execution of OnStop, instead it first finish the OnStart method and then it executes the OnStop and Positions closed event handler.
As I said each cBot/Indicator runs on a single thread, the thread can only execute one event per time, if you are inside OnTick it can't execute OnBar code or if you are inside OnStart it can't execute the code inside OnStop even if you call it from OnStart, it first finish the current event call and then the next one.
cTrader Automate uses event loop, and it calls each event sequentially when they arrive, only a single event is executed at a time.
@amusleh
amusleh
15 Apr 2022, 08:37
RE: TEST ROBOT
matthewgrayiveta said:
I didnt have before any trouble with test my robot when i update spotwere i start have this problem is not my robot is spotwere update problem
Hi,
We can't reproduce this issue, please provide a sample that can reproduce this issue and then we will be able to help you.
@amusleh
amusleh
15 Apr 2022, 08:36
RE: RE:
waym77 said:
amusleh said:
Hi,
Right now the session data is not available on Automate API, you can code it by using some fixed hours of day for each session.
We might consider adding this data in future version of cTrader Automate.
Thanks, I'll add it manually.
What are the fixed hours according to cTrader?
Hi,
cTrader uses standard market exchange opening/closing times for each session.
@amusleh
amusleh
14 Apr 2022, 11:12
Hi,
It would be very rare for all of them to be exactly equal, you have to use some kind of threshold.
Here is the code with alert:
using System;
using cAlgo.API;
using cAlgo.API.Indicators;
namespace cAlgo.Indicators
{
[Indicator(IsOverlay = true, AccessRights = AccessRights.FullAccess)]
public class IchimokuKinkoHyo : Indicator
{
[Parameter(DefaultValue = 9)]
public int periodFast { get; set; }
[Parameter(DefaultValue = 26)]
public int periodMedium { get; set; }
[Parameter(DefaultValue = 52)]
public int periodSlow { get; set; }
[Parameter(DefaultValue = 26)]
public int DisplacementChikou { get; set; }
[Parameter(DefaultValue = 26)]
public int DisplacementCloud { get; set; }
[Parameter("Threshold (Pips)", DefaultValue = 1, MinValue = 0, Group = "Alert")]
public double AlertThreshold { get; set; }
[Parameter("Sound File Path", Group = "Alert")]
public string AlertSoundFile { get; set; }
[Output("TenkanSen", Color = Colors.Red)]
public IndicatorDataSeries TenkanSen { get; set; }
[Output("Kijunsen", Color = Colors.Blue)]
public IndicatorDataSeries KijunSen { get; set; }
[Output("ChikouSpan", Color = Colors.DarkViolet)]
public IndicatorDataSeries ChikouSpan { get; set; }
[Output("SenkouSpanB", Color = Colors.Red, LineStyle = LineStyle.Lines)]
public IndicatorDataSeries SenkouSpanB { get; set; }
[Output("SenkouSpanA", Color = Colors.Green, LineStyle = LineStyle.Lines)]
public IndicatorDataSeries SenkouSpanA { get; set; }
private double maxfast, minfast, maxmedium, minmedium, maxslow, minslow;
protected override void Initialize()
{
AlertThreshold *= Symbol.PipSize;
}
public override void Calculate(int index)
{
if ((index < periodFast) || (index < periodSlow)) { return; }
maxfast = MarketSeries.High[index];
minfast = MarketSeries.Low[index];
maxmedium = MarketSeries.High[index];
minmedium = MarketSeries.Low[index];
maxslow = MarketSeries.High[index];
minslow = MarketSeries.Low[index];
for (int i = 0; i < periodFast; i++)
{
if (maxfast < MarketSeries.High[index - i]) { maxfast = MarketSeries.High[index - i]; }
if (minfast > MarketSeries.Low[index - i]) { minfast = MarketSeries.Low[index - i]; }
}
for (int i = 0; i < periodMedium; i++)
{
if (maxmedium < MarketSeries.High[index - i]) { maxmedium = MarketSeries.High[index - i]; }
if (minmedium > MarketSeries.Low[index - i]) { minmedium = MarketSeries.Low[index - i]; }
}
for (int i = 0; i < periodSlow; i++)
{
if (maxslow < MarketSeries.High[index - i]) { maxslow = MarketSeries.High[index - i]; }
if (minslow > MarketSeries.Low[index - i]) { minslow = MarketSeries.Low[index - i]; }
}
TenkanSen[index] = (maxfast + minfast) / 2;
KijunSen[index] = (maxmedium + minmedium) / 2;
ChikouSpan[index - DisplacementChikou] = MarketSeries.Close[index];
SenkouSpanA[index + DisplacementCloud] = (TenkanSen[index] + KijunSen[index]) / 2;
SenkouSpanB[index + DisplacementCloud] = (maxslow + minslow) / 2;
if (IsLastBar && Math.Abs(TenkanSen[index] - KijunSen[index]) <= AlertThreshold && Math.Abs(KijunSen[index] - SenkouSpanA[index]) <= AlertThreshold && Math.Abs(SenkouSpanA[index] - SenkouSpanB[index]) <= AlertThreshold)
{
Notifications.PlaySound(AlertSoundFile);
}
}
}
}
Changed the threshold to 0 if you want to get alerted only if they were exactly equal, otherwise set some few pips as your tolerance level.
The values of them are in double, 99.99% of the time they will not be exactly equal as some decimal place might have different value.
@amusleh
amusleh
20 Apr 2022, 09:41
Hi,
We are aware of this issue, it will be fixed on a future release.
@amusleh