Topics
Forum Topics not found
Replies
amusleh
25 May 2022, 10:58
RE: RE:
abondi said:
Hi Amusleh,
Thank you for your response.
I'm aware of these custom indicators, but they are a workaround of the actual problem.
These indicators do draw the custom interval but when you want to add other indicators like a simple SMA or EMA it will not work.
It seems it is possible to rewrite the code of the SMA or EMA to use the output of the mentioned indicators above but this is no solution when using proprietary indicators.
It would be better to tackle the problem at the source so any indicator / bot can be used with custom intervals.
Hi,
You can use the above indicators output as source for other indicators if they have a source parameter.
@amusleh
amusleh
25 May 2022, 09:29
( Updated at: 25 May 2022, 09:30 )
RE:
Hi,
You did not answer my question, why it should not be supported in the first place? Why is it marked as a bug?
It was never supported, parameter have a list of supported types, you can't use other types except them for parameters.
You are misusing parameter attribute, it's meant to be used for showing a parameter on indicator/cBot parameters window, it's linked to cTrader UI and you can't use any object you want to as a parameter.
This is and was our design, you can't blame us for your misuse of API.
The limitation wasn't there before so why is it introduced now? I would not call it a hack, but not going to argue about that because it's pointless.
It's not a new imposed limitation, it was a bug on parameter type validation and it's now fixed.
cTrader verifies if an indicator/cBot parameters are of supported types or not, because we can't show a UI for it.
So you are saying there is no support for internal indicators anymore, right? Because this is what I am arguing about all the time - it was possible prior to 4.2! I didn't have to expose the indicator to the UI and had the freedom to work with the Indicator base class as I liked. There is no difference between having multiple indicators in a single assembly versus having them split into multiple assemblies except for accessibility which you have made unsupported with this "bug fix".
I have no idea what's internal indicator, we never had such a thing, where you got the idea of creating a new indicator or robot class inside another indicator / cBot assembly? where it's documented? where you saw the GetIndicator method to be used for creating an indicator instance that is already inside the current indicator assembly?
What I'm not getting is why you create an indicator class? you don't have to, an indicator class is used for an indicator that is shown on cTrader and it's called by API, if you have some other services use another class like I showed you.
The way you used Parameter attribute was not correct, and you were exploiting a bug on parameter type validation.
Right, you are essentially going to functional programming and limiting OOP in this case. The code is just a sample to reproduce the issue, I bet you can imagine what it is going to be like to change complex projects utilizing the Indicator properties and functions by porting from the prior cTrader version to the current one like you did here.
I'm not going to argue about FP and OOP, I don't think those are related to our topic at all.
You have to use an API properly, if there was something weird possible you had to report it to us, not misuse it.
To summarize it, please correct me if I am wrong. The cTrader 4.2 raised the limitations for unexplained reasons causing old algos that were working completely fine not to work anymore. These changes are marked as a bug fix for your convenience despite no issues experienced in the past and you are unwilling to take the limitation away in the upcoming version. So I am forced to redesign the majority of my indicators to follow the strict design pattern - not being able to use the Indicator base class internally with custom parameter types. Is that correct?
We haven't imposed any new limitation, cTrader 4.2 contains some bug fixes, you were exploiting a bug on API and when it got fixed now you are complaining why we imposed new limitation?
@amusleh
amusleh
25 May 2022, 09:13
Hi,
You can change the namespace of your Resources.Designer.cs file to cAlgo.Robots and then you will be able to access the properties directly without adding any namespace using.
The resource file is generated by Visual Studio, and the name space is also set based on your project name, so it's not related to cTrader Automate.
@amusleh
amusleh
25 May 2022, 09:06
Hi,
Fractal can lag x number of bars based on your provided period number, so try to use earlier bar index when accessing data.
I can only guide you and help you regarding specific API related questions, I can't help you to fully develop your cBot or indicator.
If a value on a data series in NAN it means you haven't set the value for that index, and you have to check your code and find what's causing it.
@amusleh
amusleh
25 May 2022, 09:00
Hi,
Try this:
using System;
using System.Linq;
using cAlgo.API;
namespace cAlgo.Robots
{
[Robot(AccessRights = AccessRights.None)]
public class NewcBot : Robot
{
[Parameter("Trade Type", DefaultValue = TradeType.Buy)]
public TradeType TradeType { get; set; }
[Parameter("Symbol Name", DefaultValue = "EURUSD")]
public string SelectedSymbolName { get; set; }
protected override void OnStart()
{
CloseAllPositionsAsync(TradeType, SelectedSymbolName);
CancelAllOrdersAsync(TradeType, SelectedSymbolName);
}
private void CloseAllPositionsAsync(TradeType tradeType, string symbolName, Action<TradeResult> callback = null)
{
var positionsCopy = Positions.ToArray();
foreach (var position in positionsCopy)
{
if (position.TradeType == tradeType && position.SymbolName.Equals(symbolName, StringComparison.Ordinal))
{
ClosePositionAsync(position, callback);
}
}
}
private void CancelAllOrdersAsync(TradeType tradeType, string symbolName, Action<TradeResult> callback = null)
{
var ordersCopy = PendingOrders.ToArray();
foreach (var order in ordersCopy)
{
if (order.TradeType == tradeType && order.SymbolName.Equals(symbolName, StringComparison.Ordinal))
{
CancelPendingOrderAsync(order, callback);
}
}
}
}
}
@amusleh
amusleh
25 May 2022, 08:51
RE: RE: Please see them in the below text (I've blurred my account number):
mysassygirls said:
amusleh said:
Hi,
The received message is not well formatted, I can't read exactly what's inside it, please copy and post the exact message as text not image.
Received: |8|=|F|I|X|.|4|.|4|||9|=|1|1|2|||3|5|=|5|||3|4|=|1|||4|9|=|C|S|E|R|V|E|R|||5|0|=|Q|U|O|T|E|||5|2|=|2|0|2|2|0|5|2|3|-|0|8|:|1|3|:|1|7|.|8|8|8|||5|6|=|l|i|v|e|.|p|e|p|p|e|r|s|t|o|n|e|.|x|x|x|x|x|x|x|||5|7|=|Q|U|O|T|E|||5|8|=|R|E|T|_|I|N|V|A|L|I|D|_|D|A|T|A|||1|0|=|0|5|6||| Disconnected, reason: [Failure instance: Traceback (failure with no frames): <class 'twisted.internet.error.ConnectionDone'>: Connection was closed cleanly. ]
Hi,
I just tested Jupyter sample and it works fine, as I said most probably something is wrong with your credentials.
Here is the responses I received:
Connected
Sent: 8=FIX.4.4|9=122|35=A|49=demo.icmarkets.3279203|56=cServer|57=QUOTE|50=QUOTE|34=1|52=20220525-05:47:09|98=0|108=30|553=3279203|554=3279203|10=100|
Received: 8=FIX.4.4|9=102|35=A|34=1|49=cServer|50=QUOTE|52=20220525-05:47:10.868|56=demo.icmarkets.3279203|57=QUOTE|98=0|108=30|10=163|
Sent: 8=FIX.4.4|9=98|35=x|49=demo.icmarkets.3279203|56=cServer|57=QUOTE|50=QUOTE|34=2|52=20220525-05:47:09|320=A|559=0|10=249|
Received: 8=FIX.4.4|9=3346|35=y|34=2|49=cServer|50=QUOTE|52=20220525-05:47:10.922|56=demo.icmarkets.3279203|57=QUOTE|320=A|322=responce:A|560=0|146=122|55=1024|1007=EURCZK|1008=3|55=1|1007=EURUSD|1008=5|55=1025|1007=NZDSGD|1008=4|55=2|1007=GBPUSD|1008=5|55=1026|1007=USDTHB|1008=3|55=3|1007=EURJPY|1008=3|55=4|1007=USDJPY|1008=3|55=5|1007=AUDUSD|1008=5|55=6|1007=USDCHF|1008=5|55=7|1007=GBPJPY|1008=3|55=8|1007=USDCAD|1008=5|55=9|1007=EURGBP|1008=5|55=10|1007=EURCHF|1008=5|55=11|1007=AUDJPY|1008=3|55=12|1007=NZDUSD|1008=5|55=13|1007=CHFJPY|1008=3|55=14|1007=EURAUD|1008=5|55=15|1007=CADJPY|1008=3|55=16|1007=GBPAUD|1008=5|55=10000|1007=AUS200|1008=2|55=17|1007=EURCAD|1008=5|55=10001|1007=STOXX50|1008=2|55=18|1007=AUDCAD|1008=5|55=10002|1007=F40|1008=2|55=19|1007=GBPCAD|1008=5|55=10003|1007=DE30|1008=2|55=20|1007=AUDNZD|1008=5|55=10004|1007=HK50|1008=2|55=10005|1007=IT40|1008=2|55=21|1007=NZDJPY|1008=3|55=10006|1007=JP225|1008=2|55=22|1007=USDNOK|1008=5|55=23|1007=AUDCHF|1008=5|55=10007|1007=AEX|1008=2|55=10008|1007=WIG20|1008=2|55=24|1007=USDMXN|1008=5|55=25|1007=GBPNZD|1008=5|55=10009|1007=ES35|1008=2|55=26|1007=EURNZD|1008=5|55=10010|1007=SMI|1008=2|55=27|1007=CADCHF|1008=5|55=10011|1007=UK100|1008=2|55=10012|1007=US2000|1008=2|55=28|1007=USDSGD|1008=5|55=10013|1007=US500|1008=2|55=29|1007=USDSEK|1008=5|55=10014|1007=USTEC|1008=2|55=30|1007=NZDCAD|1008=5|55=31|1007=EURSEK|1008=5|55=10015|1007=US30|1008=2|55=10016|1007=XPDUSD|1008=2|55=32|1007=GBPSGD|1008=5|55=10017|1007=XPTUSD|1008=2|55=33|1007=EURNOK|1008=5|55=34|1007=EURHUF|1008=3|55=10018|1007=XBRUSD|1008=2|55=35|1007=USDPLN|1008=5|55=10019|1007=XTIUSD|1008=2|55=10020|1007=XNGUSD|1008=3|55=36|1007=USDDKK|1008=5|55=37|1007=GBPNOK|1008=5|55=10021|1007=BRENT|1008=2|55=38|1007=AUDDKK|1008=5|55=10022|1007=WTI|1008=2|55=39|1007=NZDCHF|1008=5|55=10023|1007=EURUSDt|1008=5|55=40|1007=GBPCHF|1008=5|55=10024|1007=DE30t|1008=1|55=41|1007=XAUUSD|1008=2|55=10025|1007=CHINA50|1008=2|55=42|1007=XAGUSD|1008=3|55=10026|1007=BTCUSD|1008=2|55=43|1007=XAUEUR|1008=2|55=10027|1007=DSHUSD|1008=2|55=44|1007=XAGEUR|1008=3|55=10028|1007=BCHUSD|1008=2|55=10029|1007=ETHUSD|1008=2|55=10030|1007=LTCUSD|1008=2|55=10031|1007=GBPTRY|1008=5|55=10032|1007=XAUAUD|1008=2|55=10033|1007=CA60|1008=2|55=10034|1007=TecDE30|1008=2|55=10035|1007=MidDE60|1008=2|55=10036|1007=NETH25|1008=2|55=10037|1007=SWI20|1008=2|55=10038|1007=SG30|1008=2|55=10039|1007=CHINAH|1008=2|55=10040|1007=NOR25|1008=2|55=10041|1007=SA40|1008=2|55=10042|1007=SE30|1008=2|55=10043|1007=USCrude100|1008=2|55=10044|1007=UKBrent100|1008=2|55=10045|1007=MidDE50|1008=2|55=10046|1007=DE40|1008=2|55=10047|1007=XAUCHF|1008=2|55=10048|1007=XAUGBP|1008=2|55=10049|1007=XAUJPY|1008=0|55=10050|1007=XAGAUD|1008=3|55=1000|1007=USDHKD|1008=4|55=1001|1007=AUDSGD|1008=5|55=1002|1007=CHFSGD|1008=5|55=1003|1007=EURDKK|1008=5|55=1004|1007=EURHKD|1008=5|55=1005|1007=EURPLN|1008=5|55=1006|1007=EURSGD|1008=5|55=1007|1007=EURTRY|1008=5|55=1008|1007=EURZAR|1008=5|55=1009|1007=GBPDKK|1008=5|55=1010|1007=GBPSEK|1008=5|55=1011|1007=NOKSEK|1008=5|55=1012|1007=USDTRY|1008=5|55=1013|1007=USDZAR|1008=5|55=1014|1007=NOKJPY|1008=3|55=1015|1007=SEKJPY|1008=3|55=1016|1007=SGDJPY|1008=3|55=1017|1007=USDHUF|1008=3|55=1018|1007=USDCZK|1008=4|55=1019|1007=USDRUB|1008=3|55=1020|1007=USDCNH|1008=5|55=1021|1007=GBPZAR|1008=4|55=1022|1007=EURMXN|1008=4|55=1023|1007=EURRUB|1008=3|10=090|
Sent: 8=FIX.4.4|9=127|35=V|49=demo.icmarkets.3279203|56=cServer|57=QUOTE|50=QUOTE|34=3|52=20220525-05:47:09|262=a|263=1|264=1|267=1|269=0|146=1|55=1|10=042|
Received: 8=FIX.4.4|9=136|35=W|34=3|49=cServer|50=QUOTE|52=20220525-05:47:10.978|56=demo.icmarkets.3279203|57=QUOTE|55=1|268=2|269=0|270=1.0706|269=1|270=1.07062|10=235|
Received: 8=FIX.4.4|9=137|35=W|34=4|49=cServer|50=QUOTE|52=20220525-05:47:12.308|56=demo.icmarkets.3279203|57=QUOTE|55=1|268=2|269=0|270=1.07061|269=1|270=1.07062|10=019|
Received: 8=FIX.4.4|9=137|35=W|34=5|49=cServer|50=QUOTE|52=20220525-05:47:12.558|56=demo.icmarkets.3279203|57=QUOTE|55=1|268=2|269=0|270=1.07061|269=1|270=1.07061|10=026|
Received: 8=FIX.4.4|9=136|35=W|34=6|49=cServer|50=QUOTE|52=20220525-05:47:12.843|56=demo.icmarkets.3279203|57=QUOTE|55=1|268=2|269=0|270=1.07059|269=1|270=1.0706|10=237|
Received: 8=FIX.4.4|9=136|35=W|34=7|49=cServer|50=QUOTE|52=20220525-05:47:15.213|56=demo.icmarkets.3279203|57=QUOTE|55=1|268=2|269=0|270=1.07058|269=1|270=1.0706|10=231|
Received: 8=FIX.4.4|9=137|35=W|34=8|49=cServer|50=QUOTE|52=20220525-05:47:17.959|56=demo.icmarkets.3279203|57=QUOTE|55=1|268=2|269=0|270=1.07062|269=1|270=1.07064|10=043|
Received: 8=FIX.4.4|9=137|35=W|34=9|49=cServer|50=QUOTE|52=20220525-05:47:18.162|56=demo.icmarkets.3279203|57=QUOTE|55=1|268=2|269=0|270=1.07062|269=1|270=1.07062|10=029|
Received: 8=FIX.4.4|9=138|35=W|34=10|49=cServer|50=QUOTE|52=20220525-05:47:18.361|56=demo.icmarkets.3279203|57=QUOTE|55=1|268=2|269=0|270=1.07061|269=1|270=1.07061|10=069|
Received: 8=FIX.4.4|9=137|35=W|34=11|49=cServer|50=QUOTE|52=20220525-05:47:18.564|56=demo.icmarkets.3279203|57=QUOTE|55=1|268=2|269=0|270=1.0706|269=1|270=1.07061|10=025|
Received: 8=FIX.4.4|9=138|35=W|34=12|49=cServer|50=QUOTE|52=20220525-05:47:19.631|56=demo.icmarkets.3279203|57=QUOTE|55=1|268=2|269=0|270=1.07062|269=1|270=1.07063|10=075|
Received: 8=FIX.4.4|9=138|35=W|34=13|49=cServer|50=QUOTE|52=20220525-05:47:19.831|56=demo.icmarkets.3279203|57=QUOTE|55=1|268=2|269=0|270=1.07063|269=1|270=1.07064|10=080|
Received: 8=FIX.4.4|9=138|35=W|34=14|49=cServer|50=QUOTE|52=20220525-05:47:20.073|56=demo.icmarkets.3279203|57=QUOTE|55=1|268=2|269=0|270=1.07061|269=1|270=1.07062|10=067|
Disconnected, reason: [Failure instance: Traceback (failure with no frames): <class 'twisted.internet.error.ConnectionLost'>: Connection to the other side was lost in a non-clean fashion: Connection lost.
]
Not sure why your response contains so many pipes, which makes it really hard to understand what's inside the message.
I used this configuration file:
{
"Host": "h51.p.ctrader.com",
"Port": 5201,
"SSL": false,
"Username": "3279203",
"Password": "3279203",
"BeginString": "FIX.4.4",
"SenderCompID": "demo.icmarkets.3279203",
"SenderSubID": "QUOTE",
"TargetCompID": "cServer",
"TargetSubID": "QUOTE",
"HeartBeat": "30"
}
It's a demo account, try this configuration file without changing anything on the sample, see if it works or not.
@amusleh
amusleh
25 May 2022, 08:01
Hi,
That's the old version JSON call, we moved all requests to Protobuf, you can find full detail with samples on Open API documentation: cTrader Open API (spotware.github.io)
@amusleh
amusleh
24 May 2022, 15:33
Hi,
Try this:
using System;
using System.Linq;
using cAlgo.API;
using cAlgo.API.Indicators;
using cAlgo.API.Internals;
using cAlgo.Indicators;
using System.Threading;
namespace cAlgo.Robots
{
[Robot(TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
public class SuperTrendReference_cBot : Robot
{
[Parameter(DefaultValue = "SuperTrendReference_cBot")]
public string cBotLabel { get; set; }
[Parameter("Serial Key", DefaultValue = "12")]
public string SerialKey { get; set; }
[Parameter("Trade Volume,in lots:", DefaultValue = 0.5, MinValue = 0.001)]
public double Lots { get; set; }
[Parameter("Martingale - Yes/No:", DefaultValue = true)]
public bool UseMartingale { get; set; }
[Parameter("Multiplication Factor:", DefaultValue = 1.5)]
public double MultiplicationFactor { get; set; }
[Parameter("Tolerance - Yes/No:", DefaultValue = true)]
public bool UseTolerance { get; set; }
[Parameter("Tolerance in pips:", DefaultValue = 10.0)]
public double TolerancePips { get; set; }
[Parameter("ATR Period", Group = ("Super Trend Indicator Inputs"), DefaultValue = 14)]
public int ST_Period { get; set; }
[Parameter("ATR Multiplier", Group = ("Super Trend Indicator Inputs"), DefaultValue = 2)]
public double ST_atrMulti { get; set; }
[Parameter("ATR Source", Group = ("Super Trend Indicator Inputs"), DefaultValue = MovingAverageType.Exponential)]
public MovingAverageType ST_AtrSource { get; set; }
[Parameter("Trading Start Hour:0-23", Group = ("Trading Hours"), DefaultValue = 11, MinValue = 0, MaxValue = 23, Step = 1)]
public int StartTimeHour { get; set; }
[Parameter("Trading Start Minute:0-59", Group = ("Trading Hours"), DefaultValue = 0, MinValue = 0, MaxValue = 59, Step = 1)]
public int StartTimeMinute { get; set; }
[Parameter("Trading End Hour:0-23", Group = ("Trading Hours"), DefaultValue = 17, MinValue = 0, MaxValue = 23, Step = 1)]
public int EndTimeHour { get; set; }
[Parameter("Trading End Minute:0-59", Group = ("Trading Hours"), DefaultValue = 0, MinValue = 0, MaxValue = 59, Step = 1)]
public int EndTimeMinute { get; set; }
[Parameter("Max Drawdown,in %:", DefaultValue = 10.0)]
public double MaxDDPrct { get; set; }
[Parameter("Coffee Break - Yes/No:", DefaultValue = true)]
public bool UseCoffeeBreak { get; set; }
[Parameter("Profit:", DefaultValue = 500.0)]
public double CBProfit { get; set; }
[Parameter("RSI Signal bar", DefaultValue = 1, MinValue = 0)]
public int SignalBar { get; set; }
private SuperTrendExperto SuperTrend_;
private double currentTradeLots;
private DateTime StartTimeHour_;
private DateTime EndTimeHour_;
private DateTime StartTimeMinute_;
private DateTime EndTimeMinute_;
private double InitialDDAccountBalance;
private double CurrentClosedPosBal;
protected override void OnStart()
{
if (SerialKey != "0")
{
Print("Serial Key is NOT valid!");
Stop();
}
SuperTrend_ = Indicators.GetIndicator<SuperTrendExperto>(ST_Period, ST_atrMulti, ST_atrMulti);
if (UseMartingale == true)
{
currentTradeLots = Lots;
}
StartTimeHour_ = Server.Time.Date.AddHours(StartTimeHour);
EndTimeHour_ = Server.Time.Date.AddHours(EndTimeHour);
StartTimeMinute_ = Server.Time.Date.AddMinutes(StartTimeMinute);
EndTimeMinute_ = Server.Time.Date.AddMinutes(EndTimeMinute);
InitialDDAccountBalance = Account.Balance;
CurrentClosedPosBal = 0.0;
}
protected override void OnTick()
{
if (IsReach_DDPrct(MaxDDPrct) == true)
{
CloseAllPositions(TradeType.Buy);
CloseAllPositions(TradeType.Sell);
Print("DD is Hit!");
InitialDDAccountBalance = Account.Balance;
CurrentClosedPosBal = 0.0;
}
}
protected override void OnBar()
{
if (IsTradingHours() == true)
{
if (SuperTrend_.LowLine.Last(SignalBar) > 0.0 && CalculatePositionsQnty(TradeType.Buy) == 0)
{
CloseAllPositions(TradeType.Sell);
if (UseMartingale == true)
UpdateTradeVolume(TradeType.Sell);
if (UseMartingale == true)
OpenMarketOrder(TradeType.Buy, currentTradeLots);
else
OpenMarketOrder(TradeType.Buy, Lots);
}
else if (SuperTrend_.HighLine.Last(SignalBar) > 0.0 && CalculatePositionsQnty(TradeType.Sell) == 0)
{
CloseAllPositions(TradeType.Buy);
if (UseMartingale == true)
UpdateTradeVolume(TradeType.Buy);
if (UseMartingale == true)
OpenMarketOrder(TradeType.Sell, currentTradeLots);
else
OpenMarketOrder(TradeType.Sell, Lots);
}
}
}
private void OpenMarketOrder(TradeType tradeType, double dLots)
{
var volumeInUnits = Symbol.QuantityToVolumeInUnits(dLots);
volumeInUnits = Symbol.NormalizeVolumeInUnits(volumeInUnits, RoundingMode.Down);
//in final version need add attempts counter
var result = ExecuteMarketOrder(tradeType, Symbol.Name, volumeInUnits, cBotLabel, null, null);
if (!result.IsSuccessful)
{
Print("Execute Market Order Error: {0}", result.Error.Value);
OnStop();
}
}
private int CalculatePositionsQnty(TradeType tradeType)
{
return Positions.FindAll(cBotLabel, Symbol.Name, tradeType).Length;
}
private void CloseAllPositions(TradeType tradeType)
{
bool isClosed = false;
foreach (var position in Positions.FindAll(cBotLabel, Symbol.Name, tradeType))
{
var result = ClosePosition(position);
if (!result.IsSuccessful)
{
Print("Closing market order error: {0}", result.Error);
}
else
{
isClosed = true;
}
}
if (isClosed)
{
Stop();
}
}
private bool IsReach_DDPrct(double DDPrctValue)
{
return ((CalculatePL() + CurrentClosedPosBal) <= (-1.0 * InitialDDAccountBalance * DDPrctValue / 100.0));
}
private double CalculatePL()
{
double CurrentPL = 0.0;
foreach (var position in Positions.FindAll(cBotLabel, Symbol.Name))
{
CurrentPL += position.NetProfit;
}
return CurrentPL;
}
private bool IsTradingHours()
{
var currentTimeHour = Server.Time.TimeOfDay.Hours;
var currentTimeMinute = Server.Time.TimeOfDay.Minutes;
if ((StartTimeHour_.Hour < currentTimeHour && EndTimeHour_.Hour > currentTimeHour) || (StartTimeHour_.Hour == currentTimeHour && StartTimeMinute_.Minute <= currentTimeMinute) || (EndTimeHour_.Hour == currentTimeHour && EndTimeMinute_.Minute >= currentTimeMinute))
return true;
return false;
}
private void UpdateTradeVolume(TradeType tradeType)
{
RefreshData();
HistoricalTrade lastClosedPosition = History.FindLast(cBotLabel, Symbol.Name, tradeType);
if (lastClosedPosition == null)
return;
CurrentClosedPosBal += lastClosedPosition.NetProfit;
if ((UseTolerance == false && lastClosedPosition.NetProfit > 0.0) || (UseTolerance == true && lastClosedPosition.Pips > TolerancePips))
{
currentTradeLots = Lots;
}
else
{
if (UseTolerance == false || (UseTolerance == true && lastClosedPosition.Pips < (-1.0 * TolerancePips)))
{
currentTradeLots *= MultiplicationFactor;
}
else
{
//same lot size
}
}
if (UseCoffeeBreak == true && lastClosedPosition.NetProfit > CBProfit)
{
Print("Coffee Break is Hit!");
Stop();
}
}
protected override void OnStop()
{
Stop();
}
}
}
I don't have the referenced indicator inside your cBot so I can't test it.
@amusleh
amusleh
24 May 2022, 12:43
Hi,
Try this:
using System;
using System.Linq;
using cAlgo.API;
using cAlgo.API.Indicators;
using cAlgo.API.Internals;
using cAlgo.Indicators;
using System.Threading;
namespace cAlgo.Robots
{
[Robot(TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
public class SuperTrendReference_cBot : Robot
{
[Parameter(DefaultValue = "SuperTrendReference_cBot")]
public string cBotLabel { get; set; }
[Parameter("Serial Key", DefaultValue = "12")]
public string SerialKey { get; set; }
[Parameter("Trade Volume,in lots:", DefaultValue = 0.5, MinValue = 0.001)]
public double Lots { get; set; }
[Parameter("Martingale - Yes/No:", DefaultValue = true)]
public bool UseMartingale { get; set; }
[Parameter("Multiplication Factor:", DefaultValue = 1.5)]
public double MultiplicationFactor { get; set; }
[Parameter("Tolerance - Yes/No:", DefaultValue = true)]
public bool UseTolerance { get; set; }
[Parameter("Tolerance in pips:", DefaultValue = 10.0)]
public double TolerancePips { get; set; }
[Parameter("ATR Period", Group = ("Super Trend Indicator Inputs"), DefaultValue = 14)]
public int ST_Period { get; set; }
[Parameter("ATR Multiplier", Group = ("Super Trend Indicator Inputs"), DefaultValue = 2)]
public double ST_atrMulti { get; set; }
[Parameter("ATR Source", Group = ("Super Trend Indicator Inputs"), DefaultValue = MovingAverageType.Exponential)]
public MovingAverageType ST_AtrSource { get; set; }
[Parameter("Trading Start Hour:0-23", Group = ("Trading Hours"), DefaultValue = 11, MinValue = 0, MaxValue = 23, Step = 1)]
public int StartTimeHour { get; set; }
[Parameter("Trading Start Minute:0-59", Group = ("Trading Hours"), DefaultValue = 0, MinValue = 0, MaxValue = 59, Step = 1)]
public int StartTimeMinute { get; set; }
[Parameter("Trading End Hour:0-23", Group = ("Trading Hours"), DefaultValue = 17, MinValue = 0, MaxValue = 23, Step = 1)]
public int EndTimeHour { get; set; }
[Parameter("Trading End Minute:0-59", Group = ("Trading Hours"), DefaultValue = 0, MinValue = 0, MaxValue = 59, Step = 1)]
public int EndTimeMinute { get; set; }
[Parameter("Max Drawdown,in %:", DefaultValue = 10.0)]
public double MaxDDPrct { get; set; }
[Parameter("Coffee Break - Yes/No:", DefaultValue = true)]
public bool UseCoffeeBreak { get; set; }
[Parameter("Profit:", DefaultValue = 500.0)]
public double CBProfit { get; set; }
[Parameter("RSI Signal bar", DefaultValue = 1, MinValue = 0)]
public int SignalBar { get; set; }
private SuperTrendExperto SuperTrend_;
private double currentTradeLots;
private DateTime StartTimeHour_;
private DateTime EndTimeHour_;
private DateTime StartTimeMinute_;
private DateTime EndTimeMinute_;
private double InitialDDAccountBalance;
private double CurrentClosedPosBal;
protected override void OnStart()
{
if (SerialKey != "0")
{
Print("Serial Key is NOT valid!");
Stop();
}
SuperTrend_ = Indicators.GetIndicator<SuperTrendExperto>(ST_Period, ST_atrMulti, ST_atrMulti);
if (UseMartingale == true)
{
currentTradeLots = Lots;
}
StartTimeHour_ = Server.Time.Date.AddHours(StartTimeHour);
EndTimeHour_ = Server.Time.Date.AddHours(EndTimeHour);
StartTimeMinute_ = Server.Time.Date.AddMinutes(StartTimeMinute);
EndTimeMinute_ = Server.Time.Date.AddMinutes(EndTimeMinute);
InitialDDAccountBalance = Account.Balance;
CurrentClosedPosBal = 0.0;
}
protected override void OnTick()
{
if (IsReach_DDPrct(MaxDDPrct) == true)
{
CloseAllPositions(TradeType.Buy);
CloseAllPositions(TradeType.Sell);
Print("DD is Hit!");
InitialDDAccountBalance = Account.Balance;
CurrentClosedPosBal = 0.0;
}
}
protected override void OnBar()
{
if (IsTradingHours() == true)
{
if (SuperTrend_.LowLine.Last(SignalBar) > 0.0 && CalculatePositionsQnty(TradeType.Buy) == 0)
{
CloseAllPositions(TradeType.Sell);
if (UseMartingale == true)
UpdateTradeVolume(TradeType.Sell);
if (UseMartingale == true)
OpenMarketOrder(TradeType.Buy, currentTradeLots);
else
OpenMarketOrder(TradeType.Buy, Lots);
}
else if (SuperTrend_.HighLine.Last(SignalBar) > 0.0 && CalculatePositionsQnty(TradeType.Sell) == 0)
{
CloseAllPositions(TradeType.Buy);
if (UseMartingale == true)
UpdateTradeVolume(TradeType.Buy);
if (UseMartingale == true)
OpenMarketOrder(TradeType.Sell, currentTradeLots);
else
OpenMarketOrder(TradeType.Sell, Lots);
}
}
}
private void OpenMarketOrder(TradeType tradeType, double dLots)
{
var volumeInUnits = Symbol.QuantityToVolumeInUnits(dLots);
volumeInUnits = Symbol.NormalizeVolumeInUnits(volumeInUnits, RoundingMode.Down);
//in final version need add attempts counter
var result = ExecuteMarketOrder(tradeType, Symbol.Name, volumeInUnits, cBotLabel, null, null);
if (!result.IsSuccessful)
{
Print("Execute Market Order Error: {0}", result.Error.Value);
OnStop();
}
}
private int CalculatePositionsQnty(TradeType tradeType)
{
return Positions.FindAll(cBotLabel, Symbol.Name, tradeType).Length;
}
private void CloseAllPositions(TradeType tradeType)
{
foreach (var position in Positions.FindAll(cBotLabel, Symbol.Name, tradeType))
{
var result = ClosePosition(position);
if (!result.IsSuccessful)
{
Print("Closing market order error: {0}", result.Error);
}
}
Stop();
}
private bool IsReach_DDPrct(double DDPrctValue)
{
return ((CalculatePL() + CurrentClosedPosBal) <= (-1.0 * InitialDDAccountBalance * DDPrctValue / 100.0));
}
private double CalculatePL()
{
double CurrentPL = 0.0;
foreach (var position in Positions.FindAll(cBotLabel, Symbol.Name))
{
CurrentPL += position.NetProfit;
}
return CurrentPL;
}
private bool IsTradingHours()
{
var currentTimeHour = Server.Time.TimeOfDay.Hours;
var currentTimeMinute = Server.Time.TimeOfDay.Minutes;
if ((StartTimeHour_.Hour < currentTimeHour && EndTimeHour_.Hour > currentTimeHour) || (StartTimeHour_.Hour == currentTimeHour && StartTimeMinute_.Minute <= currentTimeMinute) || (EndTimeHour_.Hour == currentTimeHour && EndTimeMinute_.Minute >= currentTimeMinute))
return true;
return false;
}
private void UpdateTradeVolume(TradeType tradeType)
{
RefreshData();
HistoricalTrade lastClosedPosition = History.FindLast(cBotLabel, Symbol.Name, tradeType);
if (lastClosedPosition == null)
return;
CurrentClosedPosBal += lastClosedPosition.NetProfit;
if ((UseTolerance == false && lastClosedPosition.NetProfit > 0.0) || (UseTolerance == true && lastClosedPosition.Pips > TolerancePips))
{
currentTradeLots = Lots;
}
else
{
if (UseTolerance == false || (UseTolerance == true && lastClosedPosition.Pips < (-1.0 * TolerancePips)))
{
currentTradeLots *= MultiplicationFactor;
}
else
{
//same lot size
}
}
if (UseCoffeeBreak == true && lastClosedPosition.NetProfit > CBProfit)
{
Print("Coffee Break is Hit!");
Stop();
}
}
protected override void OnStop()
{
Stop();
}
}
}
@amusleh
amusleh
24 May 2022, 12:23
RE: RE:
m4trader4 said:
Ahmad,
Open 1 sell and 1 buy position manually from Gui. Start cBot check for the 1M bar completion for results. Please check gif in the telegram for the scenario.
Positions.FindAll("")
Positions.FindAll("",symbolname) all these were working and now its not working. Pasting working code
var positionsCBS = Positions.FindAll("", Symbolname); //Print(arg2 + " " + "Yes message processed"); foreach (var psnCBS in positionsCBS) { // Print("BuySell Positon= " + psnCBS); if (psnCBS.Comment == "" || psnCBS.Comment.Contains("EP:") || psnCBS.Comment.Contains("Market")) { ClosePositionAsync(psnCBS); } }
Regards
Ahmed
Hi,
Try this:
using System;
using System.Linq;
using cAlgo.API;
namespace cAlgo.Robots
{
[Robot(AccessRights = AccessRights.FullAccess)]
public class NewcBot3 : Robot
{
protected override void OnStart()
{
//Print("Started Bot...");
//var firstResult = ExecuteMarketOrder(TradeType.Buy, SymbolName, Symbol.VolumeInUnitsMin);
//if (!firstResult.IsSuccessful)
//{
// Print("First Order not placed successfully");
//}
//var secondResult = ExecuteMarketOrder(TradeType.Buy, SymbolName, Symbol.VolumeInUnitsMin);
//if (!secondResult.IsSuccessful)
//{
// Print("Second Order not placed successfully");
//}
}
protected override void OnBar()
{
var symbolPositions = Positions.Where(position => position.SymbolName.Equals(SymbolName, StringComparison.Ordinal)).ToArray();
foreach (var position in symbolPositions)
{
ClosePosition(position);
}
}
}
}
@amusleh
amusleh
24 May 2022, 12:06
( Updated at: 24 May 2022, 12:18 )
Hi,
Why is it not supported anymore, what's the reason behind it? It's more like a hidden feature that was removed if anything.
It shouldn't be supported on the first place at all, you were able to use non supported parameter type because there was a bug on validation of indicator parameters that were initialized by GetIndicator method, and now it's fixed.
There is another similar case, in version 4.2 you can't access or call any API member from another thread, you have to use BeginInvokeOnMainThread method, due to this changes lots of indicators/cBots stopped working, but it was not a compatibility issue, it was a bug on 4.1 and it was fixed, we have stated several times on Automate API documentation that it's not thread safe but users continued to access the API members from other threads and it was working just by luck, now we have a check and it doesn't allow access from other threads.
What are other ways of passing parameters to the indicator constructor if not by decorating it with ParameterAttribute and then passing it to the GetIndicator method?
Indicator instances are created by API itself, you don't create an instance by calling the indicator constructor, so there is no way to pass an object to an indicator or cBot constructor, there was never such a feature and if you tried to find some hacks and it was working on version 4.1 there is no guarantee that it will continue to work.
You can't pass anything to an indicator or cBot before it's OnStart/Initialize method is called, this is a limitation of API and you should not try to find a workaround to bypass it.
You have to develop your cBots/Indicators by considering the API limitations, not by bypassing them.
What's the proper way of initializing internal indicators if not by using the GetIndicator?
What's an internal indicator? there should be no internal indicator, this is my first time I'm seeing an indicator inside another indicator assembly, GetIndicator method is for initializing referenced indicators not for creating new indicator class inside another indicator.
Because there are relations between the objects, C# is an object-oriented programming language. Can you modify the sample code in the first post using the technique you are describing? I am failing to understand the solution you are proposing.
I will change your design completely if it was on me I would not designed that indicator like that on the first place, you have to ask what you want to solve? what's the problem? then implement your solution based on limitations of your environment, what you did was a temporary hack the bypasses the environment limitations not solving the issue.
Indeed C# is an OOP language, but you are using a service that is not developed by you and it has it's own limitations.
Here is how I developed your indicator:
using cAlgo.API;
namespace cAlgo
{
[Indicator(AccessRights = AccessRights.None)]
public class UnsupportedParameterType : Indicator
{
[Output("Result")]
public IndicatorDataSeries Result { get; set; }
private Range _range;
protected override void Initialize()
{
_range = new Range(Bars);
}
public override void Calculate(int index)
{
Result[index] = _range.GetCalculationValue(index);
}
}
internal class Range
{
private readonly Bars _bars;
public Range(Bars bars)
{
_bars = bars;
}
public double GetCalculationValue(int index)
{
var bar = _bars[index];
return bar.High - bar.Low;
}
}
}
I need to pass an object to an indicator in the constructor, using static variables is not acceptable.
You can pass an object to another object via it's constructor if you are calling the constructor, you don't call the indicator/cBot constructor, then how you want to pass anything to it?
This is simple logic, I have developed a ton of cTrader indicators/cBots and I have never tried something that you did, it all depends on your software design and architecture skills.
The problem you are trying to solve is not passing objects to an indicator constructor, you want to send some data to another indicator instance, for that you have several options:
- Public properties
- Static data available on a separate class if you want to have access to the data during indicator initialization
Hopefully my words were useful for you.
@amusleh
amusleh
25 May 2022, 11:26
RE: RE:
jose.ayala said:
Hi,
Those data are saved on your cloud workspace.
@amusleh