Topics
Replies
jani
13 Feb 2020, 00:28
Sample code regarding 3.7. update Ticks?
I think it is great that Spotware keeps updating and improving cTrader, and the new additions on 3.7. look very nice!
However, for someone like me with very limited understanding of programming, it is sometimes hard to keep up...
I have also difficulty understanding the API reference syntax, and I really only understand code by seeing examples of it in a code snippet, indicator or cBot.
Would it be possible to get some examples of how to use these new Ticks API data?
Ticks
Automate API adds Ticks to work with tick data.
Ticks is a collection of Tick objects with following propertiesTick.Bid Tick.Ask Tick.Time
Note, in the previous versions tick data was accessible only if cBot or indicator was running on Tick1 chart and only for bid prices using old MarketSeries. With the new API you can access tick data from any timeframe and use bid and ask prices
@jani
jani
10 Feb 2020, 19:17
RE:
thanks for your reply.
I was only referring to the same instance having concurrent buy & sell open positions. I think I would need to better understand how
Positions.Find(...)
API function is treating each individual Buy and Sell position.
I was assuming that it would find any position and if the condition
if (position.Pips >= TriggerWhenGaining)
would be true, if either Sell OR Buy position were satisfying the "TriggerWhenGaining" condition. And therefore for example when Buy side qualify "TriggerWhenGaining" condition it would let the logic also to update Sell side stop without the step condition being met? ..or perhaps I have some syntax error in my thought process...LOL
@jani
jani
08 Feb 2020, 23:31
RE:
Hi Panagiotis ,
thanks for your message, sorry a bit late reply from me...
if I understood correctly
if (position.Pips >= TriggerWhenGaining)
Allow trailing to start if EITHER buy or sell position is in profit for more than TriggerWhenGaining ?,
Say we use Step=5 and buy has moved to Step but Sell only halfway, if (position.Pips >= TriggerWhenGaining) would allow also the Sell stop to be moved/trailed even though it has not yet reached the step, am I correct?
Do you think this would work?
private void SetMultiMaTrailingStop()
{
var sellPositions = Positions.FindAll(InstanceName, SymbolName, TradeType.Sell);
foreach (Position position in sellPositions)
{
double distance = position.EntryPrice - neutral1;
if (distance < BuyTriggerWhenGaining)
continue;
BuyTriggerWhenGaining += Step * Symbol.PipSize;
double newStopLossPrice = neutral1 + T3StopFromLineExit * Symbol.PipSize;
if (position.StopLoss == null || newStopLossPrice < position.StopLoss)
{
ModifyPosition(position, newStopLossPrice, position.TakeProfit);
}
BuyTriggerWhenGaining += Step * Symbol.PipSize;
}
//---------
var buyPositions = Positions.FindAll(InstanceName, SymbolName, TradeType.Buy);
foreach (Position position in buyPositions)
{
double distance = neutral1 - position.EntryPrice;
if (distance < SellTriggerWhenGaining)
continue;
double newStopLossPrice = neutral1 - T3StopFromLineExit * Symbol.PipSize;
if (position.StopLoss == null || newStopLossPrice > position.StopLoss)
{
ModifyPosition(position, newStopLossPrice, position.TakeProfit);
}
SellTriggerWhenGaining += Step * Symbol.PipSize;
}
}
Step feature is a bit hard to verify by backtesting, but I think I was getting the correct results.....
@jani
jani
20 Jan 2020, 13:16
NOTICE !!! Open indicator instances at Automate are using memory !!!
I thought that I had a memory leak issue with cTrader 3.6. as the platform was taking over 4Gb even when only one chart was open with no indicators attached (no cBots running)
Then I noticed I had many indicator instances left open at 'Automate' tab. each of these instances seems to take resources and that was causing the excessive memory-hogging!
@jani
jani
14 Dec 2019, 22:17
RE:
Thank you very much for the very helpfull example! For a beginner like myself, it is sometimes quite impossible to figure out the actual code from API reference.
Could any tell how can I draw histograms with opacity? I have :
[Output("Histogram Down", PlotType = PlotType.Histogram, LineColor = "Red")]
public IndicatorDataSeries HistogramNegative { get; set; }
How can I use in this public output parameter definition the below opacity setting?:
Color color = Color.FromArgb(50, Color.Red);
@jani
jani
30 Nov 2019, 22:39
ChartObject.DrawLine definition missing
Spotware said:
Dear Trader,
Please be advised that you can Draw the lines with using ChartObject.DrawLine function. You can then refer to the respective objects. /api/reference/internals/chartobjects/drawline
Hello,
Can you please tell me where the API reference for ChartObject.DrawLine is?
The above url /api/reference/internals/chartobjects/drawline you posted above is not valid and returns:
The server returned a "404 Not Found".
I tried to search everywhere and could not find anything.
@jani
jani
25 Nov 2019, 23:21
RE:
Panagiotis Charalampous said:
Hi Anton,
Here is how
Positions.Where(x => x.Label == "My Label").OrderByDescending(x => x.EntryTime).First();Best Regards,
Panagiotis
Could you show an example how this is used in a cBot? For example if I want to print out the last opened position time?
I'm trying to limit trade openings OnTick with a timer or a bar counter. Would be nice to have an example code for this I know many other people are looking for the same thing...
@jani
jani
20 Nov 2019, 23:56
Trailing Stop Loss with Trailing Distance and Step
Hello,
thank you for the example. It is really valuable to get these examples here, especially for a beginner programmer like myself.
It would be great if you could show how to add a "STEP to the trailing stop. More often than not, it is not necessary to update the trailing stop on every tick advanced to the trade's direction and it would save a lot of resources to add a "STEP" to the trail, so that the trailing stop is only updated when price has moved the "STEP" amount to profit.
Below is my version of a trailing stop function (stop is trailing a custom indicator value : maketemaExit(1) )
private void SetT3ExitTrailingStop() { var sellPositions = Positions.FindAll(InstanceName, Symbol, TradeType.Sell); foreach (Position position in sellPositions) { double distance = position.EntryPrice - maketemaExit(1); if (distance < MinT3DistanceExit * Symbol.PipSize) continue; double newStopLossPrice = maketemaExit(1) + T3StopFromLineExit * Symbol.PipSize; if (position.StopLoss == null || newStopLossPrice < position.StopLoss) { ModifyPosition(position, newStopLossPrice, position.TakeProfit); } } var buyPositions = Positions.FindAll(InstanceName, Symbol, TradeType.Buy); foreach (Position position in buyPositions) { double distance = maketemaExit(1) - position.EntryPrice; if (distance < MinT3DistanceExit * Symbol.PipSize) continue; double newStopLossPrice = maketemaExit(1) - T3StopFromLineExit * Symbol.PipSize; if (position.StopLoss == null || newStopLossPrice > position.StopLoss) { ModifyPosition(position, newStopLossPrice, position.TakeProfit); } } }
@jani
jani
10 Nov 2019, 16:32
RE:
Panagiotis Charalampous said:
Hi Jan,
Shouldn't the bar counter be after the actual trade execution logic?
The counter starts after a position is opened as per the requirement
How about resetting the counter after the trade is closed?
This is just an example on how to implement such logic. Further to that, each one needs to adjust it on his cBot logic.
Best Regards,
Panagiotis
Ok, Thank you, I understand.
@jani
jani
09 Nov 2019, 20:29
( Updated at: 21 Dec 2023, 09:21 )
RE:
Drummond360 said:
Hi All,
I using the code below to open and clsoe positions upon spread size. As you can see the MaxSpread parameter is set to 1 so it should open positions when the spread is < 1 and close them when the spread is > 1 but it isn't respecting these levels.
The screen shot shows the trade log with all the spread is regularly above 1 and I can confirm that it also prints the spread ot be regularly below 1...
Can anyone spot the fault in my code, it seems too simple to get wrong!
using System; using System.Linq; using System.Collections.Generic; using cAlgo.API; using cAlgo.API.Requests; using cAlgo.API.Indicators; using cAlgo.API.Internals; using cAlgo.Indicators; namespace cAlgo { [Robot(TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)] public class Hedging2positionsonly : Robot { [Parameter("Max Spread", DefaultValue = 0.0, MinValue = -5.0)] public double MaxSpread { get; set; } string label = "Spread Test"; protected override void OnStart() { } protected override void OnTick() { var longPosition = Positions.Find(label, Symbol, TradeType.Buy); var shortPosition = Positions.Find(label, Symbol, TradeType.Sell); //var spread = Symbol.Spread / Symbol.PipSize; var spread = Symbol.Ask - Symbol.Bid; //var spread = Math.Round(Symbol.Spread / Symbol.PipSize, 1); Print("Spread is " + spread + " Symbol.Spread Value = " + Symbol.Spread); { if (shortPosition == null && spread <= MaxSpread) { ExecuteMarketOrder(TradeType.Sell, Symbol, 1000, label); Print(" enterered short, var spread is " + spread + " MaxSpread = " + MaxSpread); } if (longPosition == null && spread <= MaxSpread) { ExecuteMarketOrder(TradeType.Buy, Symbol, 1000, label); Print(" entered long, var spread is " + spread + " MaxSpread = " + MaxSpread); } } var symbolSearch = Positions.FindAll(label, Symbol); if (spread >= MaxSpread) { foreach (Position position in symbolSearch) { ClosePosition(position); Print("Exit because Spread @ " + spread + " closing positions"); } } } } }
Many thanks in advance, Drummond...
I think you just need to add:
if (shortPosition == null && spread <= MaxSpread*Symbol.PipSize)
@jani
jani
07 Nov 2019, 19:31
RE:
Panagiotis Charalampous said:
Hi irmscher,
Yes you can specify market range in the ExecuteMarketOrder function.
Best Regards,
Panagiotis
Hello,
can you please give some examples of ::
double basePrice
in ExecuteMarketRangeOrder?
@jani
jani
07 Nov 2019, 16:32
RE:
Panagiotis Charalampous said:
Hi marwaha1@gmail.com,
See below
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.None)] public class NewcBot : Robot { [Parameter(DefaultValue = 0.0)] public double Parameter { get; set; } private int _barCount; private bool _startCounting; protected override void OnStart() { Positions.Opened += OnPositionsOpened; } void OnPositionsOpened(PositionOpenedEventArgs obj) { _startCounting = true; } protected override void OnBar() { if (_startCounting) _barCount++; } protected override void OnStop() { // Put your deinitialization logic here } } }Let me know if this helps,
Best Regards,
Panagiotis
Shouldn't the bar counter be after the actual trade execution logic? How about resetting the counter after the trade is closed?
@jani
jani
07 Nov 2019, 15:40
RE:
Spotware said:
Dear hungtonydang,
If you wish to set the _lastExecutedOrder only whenever an order is executed, you should apply the following changes to your code.
First of all you need to an event handler for the Positions.Opened event as follows
protected override void OnStart() { BB = Indicators.BollingerBands(Source, Periods, Deviations, MAType); Positions.Opened += OnPositionsOpened; }Then in the event handler you can set the _lastExecutedOrder. See below
void OnPositionsOpened(PositionOpenedEventArgs obj) { _lastExecutedOrder = DateTime.Now; }See the full modified code below
using System; using System.Linq; using cAlgo.API; using cAlgo.API.Requests; using cAlgo.API.Collections; using cAlgo.API.Indicators; using cAlgo.API.Internals; using cAlgo.Indicators; using System.Threading; using System.Threading.Tasks; namespace cAlgo { [Robot(TimeZone = TimeZones.TasmaniaStandardTime, AccessRights = AccessRights.None)] public class HunterBB : Robot { [Parameter("Source")] public DataSeries Source { get; set; } [Parameter("Stop Loss (pips)", DefaultValue = 40, MinValue = 1)] public int StopLossInPips { get; set; } [Parameter("Take Profit (pips)", DefaultValue = 40, MinValue = 1)] public int TakeProfitInPips { get; set; } [Parameter("Quantity (Lots)", DefaultValue = 1, MinValue = 0.01, Step = 0.01)] public double Quantity { get; set; } [Parameter("Cooldown (hours)", DefaultValue = 2, MinValue = 1, Step = 1)] public double CD { get; set; } [Parameter("Bollinger Bands Deviations", DefaultValue = 2)] public double Deviations { get; set; } [Parameter("Bollinger Bands Periods", DefaultValue = 20)] public int Periods { get; set; } [Parameter("Bollinger Bands MA Type")] public MovingAverageType MAType { get; set; } [Parameter("Position Id", DefaultValue = "Pid")] public string PositionId { get; set; } public Position position; private DateTime _lastExecutedOrder; BollingerBands BB; protected override void OnStart() { BB = Indicators.BollingerBands(Source, Periods, Deviations, MAType); Positions.Opened += OnPositionsOpened; } void OnPositionsOpened(PositionOpenedEventArgs obj) { _lastExecutedOrder = DateTime.Now; } protected override void OnBar() { var midbb = BB.Main.Last(0); var topnow = BB.Top.Last(0); var bottomnow = BB.Bottom.Last(0); var volumeInUnits = Symbol.QuantityToVolume(Quantity); var expiry = Time.AddHours(1); if (_lastExecutedOrder.AddHours(CD) < DateTime.Now) { //higher than indicator target price PlaceLimitOrder(TradeType.Sell, Symbol, volumeInUnits, topnow + 5 * Symbol.PipSize, PositionId, StopLossInPips, null, expiry); //lower than indicator target price PlaceLimitOrder(TradeType.Buy, Symbol, volumeInUnits, bottomnow - 5 * Symbol.PipSize, PositionId, StopLossInPips, null, expiry); } foreach (var position in Positions) { if (Symbol.Code == position.SymbolCode) { ModifyPositionAsync(position, position.StopLoss, midbb); Print("New Position TP price is {0}", position.TakeProfit); } } } protected override void OnStop() { Stop(); } } }Let us know if this is what you are looking for.
Best Regards,
cTrader Team
Problem with this code is that it is not working in backtesting as DateTime.Now give current computer time not the server time backtesting is reading.
if (_lastExecutedOrder.AddHours(CD) < DateTime.Now)
I would never run any cBot live before I have backtested it.... But thanks for your effort. I'll try to look if I can find a solution
@jani
jani
07 Nov 2019, 12:51
RE:
Panagiotis Charalampous said:
Hi Jan,
In the posts above I forgot to mention that you also need to install the extension for VS2017. You can also consider VS 2019 since you are upgrading.
Best Regards,
Panagiotis
Hello,
Thank for the reply.
Currently trying to uninstall VS 2015 but it seems to act like a virus and removing it is not easy... have to browse through GitHub for solutions...
Is there any way to instruct cAlgo to open VS 2017 instead of the broken 2015?
@jani
jani
07 Nov 2019, 12:35
RE:
Panagiotis Charalampous said:
Hi Piero,
Visual Studio extension supports both 2015 and 2017 so there is nothing special you need to do. Just install VS 2017 and make is the default program to open solution files. The next time you will click on Edit in Visual Studio VS 2017 should launch instead.
Best Regards,
Panagiotis
Hello,
i made VS 2017 my default program to open .algo files but cTrader is still opening with VS 20+15. Do I need to uninstall 2015? 2015 is very unstable on my computer and keeps crashing when building cAlgo
@jani
jani
07 Nov 2019, 01:40
RE:
admin said:
UPDATED
This code is a reference to handling multiple positions. This robot is intended to be used as an example and does not guarantee any particular outcome or profit of any kind.
using cAlgo.API; using cAlgo.API.Indicators; namespace cAlgo.Robots { [Robot] public class SampleMultiplePositions : Robot { private MovingAverage _fastMa; private MovingAverage _slowMa; [Parameter(DefaultValue = "Sample cBot")] public string cBotLabel { get; set; } [Parameter] public DataSeries SourceSeries { get; set; } [Parameter("MA Type")] public MovingAverageType MAType { get; set; } [Parameter("Slow Periods", DefaultValue = 10)] public int SlowPeriods { get; set; } [Parameter("Fast Periods", DefaultValue = 5)] public int FastPeriods { get; set; } [Parameter(DefaultValue = 100000)] public int Volume { get; set; } [Parameter("Stop Loss (pips)", DefaultValue = 100)] public int StopLoss { get; set; } [Parameter("Take Profit (pips)", DefaultValue = 100)] public int TakeProfit { get; set; } [Parameter("Trigger (pips)", DefaultValue = 10)] public int Trigger { get; set; } [Parameter("Trailing Stop (pips)", DefaultValue = 10)] public int TrailingStop { get; set; } [Parameter("MinBalance", DefaultValue = 5000)] public double MinBalance { get; set; } [Parameter("MinLoss", DefaultValue = -200.0)] public double MinLoss { get; set; } [Parameter(DefaultValue = 3)] public int MaxPositions { get; set; } protected override void OnStart() { _fastMa = Indicators.MovingAverage(SourceSeries, FastPeriods, MAType); _slowMa = Indicators.MovingAverage(SourceSeries, SlowPeriods, MAType); Positions.Opened += PositionsOnOpened; Positions.Closed += PositionsOnClosed; } protected override void OnBar() { var cBotPositions = Positions.FindAll(cBotLabel); if (cBotPositions.Length > MaxPositions) return; var currentSlowMa = _slowMa.Result.Last(0); var currentFastMa = _fastMa.Result.Last(0); var previousSlowMa = _slowMa.Result.Last(1); var previousFastMa = _fastMa.Result.Last(1); // Condition to Buy if (previousSlowMa > previousFastMa && currentSlowMa <= currentFastMa) ExecuteMarketOrder(TradeType.Buy, Symbol, Volume, cBotLabel, StopLoss, TakeProfit); else if (previousSlowMa < previousFastMa && currentSlowMa >= currentFastMa) ExecuteMarketOrder(TradeType.Sell, Symbol, Volume, cBotLabel, StopLoss, TakeProfit); // Some condition to close all positions if (Account.Balance < MinBalance) foreach (var position in cBotPositions) ClosePosition(position); // Some condition to close one position foreach (var position in cBotPositions) if (position.GrossProfit < MinLoss) ClosePosition(position); // Trailing Stop for all positions SetTrailingStop(); } private void PositionsOnOpened(PositionOpenedEventArgs obj) { Position openedPosition = obj.Position; if (openedPosition.Label != cBotLabel) return; Print("position opened at {0}", openedPosition.EntryPrice); } private void PositionsOnClosed(PositionClosedEventArgs obj) { Position closedPosition = obj.Position; if (closedPosition.Label != cBotLabel) return; Print("position closed with {0} gross profit", closedPosition.GrossProfit); } /// <summary> /// When the profit in pips is above or equal to Trigger the stop loss will start trailing the spot price. /// TrailingStop defines the number of pips the Stop Loss trails the spot price by. /// If Trigger is 0 trailing will begin immediately. /// </summary> private void SetTrailingStop() { var sellPositions = Positions.FindAll(cBotLabel, Symbol, TradeType.Sell); foreach (Position position in sellPositions) { double distance = position.EntryPrice - Symbol.Ask; if (distance < Trigger*Symbol.PipSize) continue; double newStopLossPrice = Symbol.Ask + TrailingStop*Symbol.PipSize; if (position.StopLoss == null || newStopLossPrice < position.StopLoss) ModifyPosition(position, newStopLossPrice, position.TakeProfit); } var buyPositions = Positions.FindAll(cBotLabel, Symbol, TradeType.Buy); foreach (Position position in buyPositions) { double distance = Symbol.Bid - position.EntryPrice; if (distance < Trigger*Symbol.PipSize) continue; double newStopLossPrice = Symbol.Bid - TrailingStop*Symbol.PipSize; if (position.StopLoss == null || newStopLossPrice > position.StopLoss) ModifyPosition(position, newStopLossPrice, position.TakeProfit); } } } }
Correction to this code, if you want only one opened position when MaxPositions is set to 1 you should put:
if (cBotPositions.Length >= MaxPositions) return;
NOT
if (cBotPositions.Length > MaxPositions) return;
Above will give you 2 open positions for MaxPosition value 1
@jani
jani
02 Nov 2019, 19:34
Add this to Calculate:
public override void Calculate(int index) { if (IsLastBar) { if (IsLastBar) { if (index != lastindex) lastindex = index; else return; }
...And to Parameters:
int lastindex = 0;
That should do it
If I only need values on closed bars. I use this to save CPU resources.
@jani
jani
20 Feb 2020, 13:09
OpenTime.GetIndexByTime replaced by what?
It's quite frustrating to run into warnings and error messages due to thwe 3,7 changes and there is no instructions on how to replace the old code!
for example, I have:
....
I cannot find anywhere how to replace
I tried just adding
instead of
but still getting an error message, and the problem is the
I just cannot find anywhere what to replace it with?
I also have:
What to replace "Open" with?
API reference is a nightmare to try to find anything (expecially since I do not even know what I'm looking for as old API definitions are removed and new ones I'm not familiar with) and if I do find syntax I usually do not understand it because there are no or only a few short examples...
Spotware , when you make large changes like 3.7. updates to you API code, please help us less professional programmers to translate the code, that is if you want to keep people like me here... Would it be totally impossible to have the error message tell what to replace old code with?
@jani