Topics
Forum Topics not found
Replies
amusleh
12 Apr 2022, 09:57
( Updated at: 14 Apr 2022, 18:26 )
Hi,
The amount of historical data that is available for a symbol depends on when your broker started using cTrader, this same data is also used in your broker cTrader back tester.
If there is not enough historical data available for your broker then you can switch to another older cTrader broker.
Usually most symbols has at least a year or two historical data for most brokers.
There is no reason for Spotware or your broker to impose limitations on amount of historical data that is available for your indicators or cBots.
A symbol price OHLC or tick data is generated when traders trade that symbol on that broker, cTrader uses each bid tick to generate trend bar or OHLC data, so for the time that your broker was not using cTrader how can it provide historical price data? because there was no data at all.
The longer your broker was using cTrader the more historical data it will have for symbols.
You can try different cTrader brokers demo accounts to check which broker has the longest historical data, it differs for each broker.
It's not related at all to being ECN or not.
@amusleh
amusleh
11 Apr 2022, 16:03
( Updated at: 14 Apr 2022, 18:26 )
Hi,
You can load as much data as available for a symbol from your broker by using Bars.LoadMoreHistory, if it doesn't load more data then it means you have already loaded all available data for the symbol time frame.
Here is an indicator example that loads all available data for a symbol:
using cAlgo.API;
namespace cAlgo
{
[Indicator(IsOverlay = true, TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
public class NewIndicator : Indicator
{
protected override void Initialize()
{
// If new bars loaded indicator will be
// re-initialized otherwise LoadMoreHistory will
// return 0 and the loop will be stopped.
// For cBots loading more data will
// not reload the running cBot instance
while (Bars.LoadMoreHistory() > 0)
{
}
Print("First Bar Open Time: {0:dd/MM/yyyy HH:mm:ss}", Bars[0].OpenTime);
}
public override void Calculate(int index)
{
}
}
}
Result:
11/04/2022 13:01:25.493 | First Bar Open Time: 01/10/2010 00:00:00
@amusleh
amusleh
11 Apr 2022, 14:32
Hi,
The Open API returns the last closed bar data if you pass right parameters to trend bar request.
To get only the last closed bar set the to timestamp to now and request count field to 1, then it will return only the last bar data.
If you are using our Open API Python package (OpenApiPy) there was an issue on it's samples related to Python date time to Unix time conversion, we fixed it, please update your samples.
@amusleh
amusleh
11 Apr 2022, 13:32
( Updated at: 19 Mar 2025, 08:57 )
Hi,
Version 4.2 is in beta test, we don't have any exact release date for it yet.
We are testing and collecting bug reports from users right now for 4.2.
If your indicator code is visible in 4.1 and not visible on 4.2 code editor, then please send us via email the indicator ",algo" file with it's solution directory which is inside cAlgo/sources/Indicators folder.
Our email: support@ctrader.com
@amusleh
amusleh
11 Apr 2022, 13:29
( Updated at: 11 Apr 2022, 14:35 )
Hi,
The max lots per split can't be greater than lots as lots is the total volume you want to split in smaller parts, max lots if the maximum allowed value for a split of lots.
And during testing I found some issues on my code, please use this updated version:
using System;
using System.Linq;
using cAlgo.API;
using cAlgo.API.Indicators;
using cAlgo.API.Internals;
namespace cAlgo.Robots
{
[Robot(TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
public class IcebergDemo : Robot
{
[Parameter("Label", DefaultValue = "_")]
public string _name { get; set; }
[Parameter("Maximum Visible Lots", Group = "Iceberg Settings", DefaultValue = 1, MaxValue = 100, MinValue = 1, Step = 1)]
public double _maxvisiblelots { get; set; }
[Parameter("Total Lots Needed", Group = "Risk", DefaultValue = 1.0, MaxValue = 100.0, MinValue = 0.01, Step = 0.01)]
public double _total_lots_needed { get; set; }
[Parameter("Stop Loss", Group = "Risk", DefaultValue = 10, MaxValue = 10000, MinValue = 0.1, Step = 0.1)]
public double _stoploss { get; set; }
[Parameter("Take Profit", Group = "Risk", DefaultValue = 15, MaxValue = 10000, MinValue = 0.1, Step = 0.1)]
public double _takeprofit { get; set; }
private bool _buy, _sell;
private MovingAverage _fast;
private MovingAverage _slow;
protected override void OnStart()
{
_fast = Indicators.MovingAverage(Bars.ClosePrices, 12, MovingAverageType.Exponential);
_slow = Indicators.MovingAverage(Bars.ClosePrices, 26, MovingAverageType.Exponential);
}
protected override void OnBar()
{
var ActiveBuy = Positions.Find(_name, Symbol.Name, TradeType.Buy);
var ActiveSell = Positions.Find(_name, Symbol.Name, TradeType.Sell);
_buy = _fast.Result.HasCrossedAbove(_slow.Result.Last(1), 1);
_sell = _fast.Result.HasCrossedBelow(_slow.Result.Last(1), 1);
double[] volumes = GetVolumeSplits(_total_lots_needed, _maxvisiblelots);
if (volumes.Sum() != Symbol.QuantityToVolumeInUnits(_total_lots_needed))
{
throw new InvalidOperationException(string.Format("Volumes doesn't match, lots sum: {0} | lots to Split: {1} | max split size: {2} | # of splits: {3}", Symbol.VolumeInUnitsToQuantity(volumes.Sum()), _total_lots_needed, _maxvisiblelots, volumes.Length));
}
if (_buy && ActiveBuy == null)
{
for (var i = 0; i < volumes.Length; i++)
{
ExecuteMarketOrder(TradeType.Buy, SymbolName, volumes[i], _name, _stoploss, _takeprofit, History.Count.ToString());
}
}
if (_sell && ActiveSell == null)
{
for (var i = 0; i < volumes.Length; i++)
{
ExecuteMarketOrder(TradeType.Sell, SymbolName, volumes[i], _name, _stoploss, _takeprofit, History.Count.ToString());
}
}
}
private double[] GetVolumeSplits(double lots, double maxLotsPerSplit)
{
if (maxLotsPerSplit > lots) throw new InvalidOperationException("maxLotsPerSplit can't be greater than lots");
var modulus = lots % maxLotsPerSplit;
var numberOfFragments = Convert.ToInt32((lots - modulus) / maxLotsPerSplit);
if (modulus > 0) numberOfFragments++;
var lotsPerFragement = lots / numberOfFragments;
var unitsPerFragment = Symbol.QuantityToVolumeInUnits(lotsPerFragement);
var unitsPerFragementNormalized = Symbol.NormalizeVolumeInUnits(unitsPerFragment, RoundingMode.Up);
var volumes = new double[numberOfFragments];
for (var i = 0; i < numberOfFragments; i++)
{
volumes[i] = i == volumes.Length - 1 && modulus > 0 ? unitsPerFragment - ((unitsPerFragementNormalized - unitsPerFragment) * (volumes.Length - 1)) : unitsPerFragementNormalized;
}
return volumes;
}
}
}
I tested with 3.75 and 3.5 lots and 1 for max lots per split and it worked fine.
I modified your code, the method itself does all the calculation, you don't have to repeat it on your calculate method, just use the method output for your orders.
Also I used History.Count for order comments, to link splits in history for checking.
@amusleh
amusleh
11 Apr 2022, 12:33
Hi,
We are aware of this issue and it's fixed on cTrader 4.2.
But it works if you use ticks inside cBot itself.
Here is an example:
using cAlgo.API;
namespace cAlgo.Robots
{
[Robot(TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
public class NewcBot : Robot
{
private Ticks _ticks;
protected override void OnStart()
{
// Getting a symbol ticks data
_ticks = MarketData.GetTicks(SymbolName);
// Subscribing to upcoming ticks
_ticks.Tick += Ticks_Tick;
}
private void Ticks_Tick(TicksTickEventArgs obj)
{
// Printing Last tick inside Ticks collection
Print("Bid: {0} | Ask: {1} | Time: {2:dd/MM/yyyy HH:mm:ss}", obj.Ticks.LastTick.Bid, obj.Ticks.LastTick.Ask, obj.Ticks.LastTick.Time);
}
}
}
Result:
11/04/2022 09:24:02.489 | Reloaded
11/04/2022 09:23:57.208 | Reloaded
11/04/2022 09:23:53.693 | Reloaded
29/03/2022 23:05:20.667 | Backtesting was stopped
29/03/2022 23:05:20.667 | Bid: 1.10928 | Ask: 1.10928 | Time: 29/03/2022 23:05:20
29/03/2022 23:05:20.412 | Bid: 1.10928 | Ask: 1.1093 | Time: 29/03/2022 23:05:20
29/03/2022 23:05:18.068 | Bid: 1.10929 | Ask: 1.1093 | Time: 29/03/2022 23:05:18
29/03/2022 23:05:14.467 | Bid: 1.10929 | Ask: 1.10931 | Time: 29/03/2022 23:05:14
29/03/2022 23:05:14.263 | Bid: 1.10929 | Ask: 1.1093 | Time: 29/03/2022 23:05:14
29/03/2022 23:05:10.745 | Bid: 1.10927 | Ask: 1.10929 | Time: 29/03/2022 23:05:10
29/03/2022 23:05:10.503 | Bid: 1.10926 | Ask: 1.10929 | Time: 29/03/2022 23:05:10
29/03/2022 23:05:07.679 | Bid: 1.10927 | Ask: 1.10929 | Time: 29/03/2022 23:05:07
29/03/2022 23:05:07.477 | Bid: 1.10927 | Ask: 1.10928 | Time: 29/03/2022 23:05:07
29/03/2022 23:05:04.379 | Bid: 1.10927 | Ask: 1.10929 | Time: 29/03/2022 23:05:04
29/03/2022 23:05:04.178 | Bid: 1.10931 | Ask: 1.10933 | Time: 29/03/2022 23:05:04
29/03/2022 23:05:02.903 | Bid: 1.10935 | Ask: 1.10936 | Time: 29/03/2022 23:05:02
29/03/2022 23:04:54.160 | Bid: 1.10935 | Ask: 1.10935 | Time: 29/03/2022 23:04:54
29/03/2022 23:04:53.863 | Bid: 1.10934 | Ask: 1.10934 | Time: 29/03/2022 23:04:53
29/03/2022 23:04:53.655 | Bid: 1.10933 | Ask: 1.10933 | Time: 29/03/2022 23:04:53
29/03/2022 23:04:52.772 | Bid: 1.10931 | Ask: 1.10932 | Time: 29/03/2022 23:04:52
29/03/2022 23:04:49.771 | Bid: 1.10931 | Ask: 1.10931 | Time: 29/03/2022 23:04:49
29/03/2022 23:04:49.270 | Bid: 1.1093 | Ask: 1.1093 | Time: 29/03/2022 23:04:49
29/03/2022 23:04:48.812 | Bid: 1.10931 | Ask: 1.10931 | Time: 29/03/2022 23:04:48
29/03/2022 23:04:48.610 | Bid: 1.10932 | Ask: 1.10932 | Time: 29/03/2022 23:04:48
29/03/2022 23:04:43.949 | Bid: 1.10933 | Ask: 1.10933 | Time: 29/03/2022 23:04:43
29/03/2022 23:04:43.684 | Bid: 1.10934 | Ask: 1.10934 | Time: 29/03/2022 23:04:43
29/03/2022 23:04:43.480 | Bid: 1.10936 | Ask: 1.10936 | Time: 29/03/2022 23:04:43
29/03/2022 23:04:36.142 | Bid: 1.10938 | Ask: 1.10938 | Time: 29/03/2022 23:04:36
29/03/2022 23:04:35.273 | Bid: 1.10938 | Ask: 1.10939 | Time: 29/03/2022 23:04:35
29/03/2022 23:04:25.332 | Bid: 1.10938 | Ask: 1.10938 | Time: 29/03/2022 23:04:25
29/03/2022 23:04:24.781 | Bid: 1.10938 | Ask: 1.10939 | Time: 29/03/2022 23:04:24
29/03/2022 23:04:23.446 | Bid: 1.10938 | Ask: 1.10938 | Time: 29/03/2022 23:04:23
29/03/2022 23:04:22.167 | Bid: 1.10939 | Ask: 1.1094 | Time: 29/03/2022 23:04:22
29/03/2022 23:04:21.958 | Bid: 1.10939 | Ask: 1.10939 | Time: 29/03/2022 23:04:21
29/03/2022 23:04:21.558 | Bid: 1.10939 | Ask: 1.1094 | Time: 29/03/2022 23:04:21
@amusleh
amusleh
11 Apr 2022, 12:02
Hi,
It looks like a Pip related issue with your system supported TLS not related to our package.
Here are some links that can help you:
[Solved] Could not find a version that satisfies the requirement - Exception Error (exerror.com)
@amusleh
amusleh
11 Apr 2022, 11:59
Hi,
You should open Automate related thread under automate section of forum not under cTrader desktop.
Regarding your question, you can use History, it contains all your account historical trades with all of their data, example:
using System.Linq;
using cAlgo.API;
namespace NewcBot
{
[Robot(AccessRights = AccessRights.None)]
public class NewcBot : Robot
{
protected override void OnStart()
{
var lastTwoTrades = History.OrderByDescending(trade => trade.ClosingTime).Take(2).ToArray();
foreach (var trade in lastTwoTrades)
{
Print("{0} | {1} | {2} | {3} | {4} | {5} | {6} | {7}", trade.SymbolName, trade.TradeType, trade.VolumeInUnits, trade.EntryPrice, trade.ClosingPrice, trade.Pips, trade.NetProfit, trade.Commissions); ;
}
}
}
}
@amusleh
amusleh
10 Apr 2022, 09:48
Hi,
I just tested by uninstalling and reinstalling it, and it works fine, result:
PS C:\Users\afhac\source\OpenApiPy> pip uninstall ctrader-open-api
Found existing installation: ctrader-open-api 0.9.0
Uninstalling ctrader-open-api-0.9.0:
Would remove:
c:\users\afhac\appdata\local\programs\python\python39\lib\site-packages\ctrader_open_api-0.9.0.dist-info\*
c:\users\afhac\appdata\local\programs\python\python39\lib\site-packages\ctrader_open_api\*
c:\users\afhac\appdata\local\programs\python\python39\lib\site-packages\license
Proceed (Y/n)? y
Successfully uninstalled ctrader-open-api-0.9.0
PS C:\Users\afhac\source\OpenApiPy> pip install ctrader-open-api
Collecting ctrader-open-api
Using cached ctrader_open_api-0.9.0-py3-none-any.whl (29 kB)
Requirement already satisfied: protobuf==3.19.1 in c:\users\afhac\appdata\local\programs\python\python39\lib\site-packages (from ctrader-open-api) (3.19.1)
Requirement already satisfied: Twisted==21.7.0 in c:\users\afhac\appdata\local\programs\python\python39\lib\site-packages (from ctrader-open-api) (21.7.0)
Requirement already satisfied: Automat>=0.8.0 in c:\users\afhac\appdata\local\programs\python\python39\lib\site-packages (from Twisted==21.7.0->ctrader-open-api) (20.2.0)
Requirement already satisfied: constantly>=15.1 in c:\users\afhac\appdata\local\programs\python\python39\lib\site-packages (from Twisted==21.7.0->ctrader-open-api) (15.1.0)
Requirement already satisfied: twisted-iocpsupport~=1.0.0 in c:\users\afhac\appdata\local\programs\python\python39\lib\site-packages (from Twisted==21.7.0->ctrader-open-api) (1.0.2)
Requirement already satisfied: typing-extensions>=3.6.5 in c:\users\afhac\appdata\local\programs\python\python39\lib\site-packages (from Twisted==21.7.0->ctrader-open-api) (4.0.0)
Requirement already satisfied: zope.interface>=4.4.2 in c:\users\afhac\appdata\local\programs\python\python39\lib\site-packages (from Twisted==21.7.0->ctrader-open-api) (5.4.0)
Requirement already satisfied: incremental>=21.3.0 in c:\users\afhac\appdata\local\programs\python\python39\lib\site-packages (from Twisted==21.7.0->ctrader-open-api) (21.3.0)
Requirement already satisfied: hyperlink>=17.1.1 in c:\users\afhac\appdata\local\programs\python\python39\lib\site-packages (from Twisted==21.7.0->ctrader-open-api) (21.0.0)
Requirement already satisfied: attrs>=19.2.0 in c:\users\afhac\appdata\local\programs\python\python39\lib\site-packages (from Twisted==21.7.0->ctrader-open-api) (21.2.0)
Requirement already satisfied: six in c:\users\afhac\appdata\local\programs\python\python39\lib\site-packages (from Automat>=0.8.0->Twisted==21.7.0->ctrader-open-api) (1.16.0)
Requirement already satisfied: idna>=2.5 in c:\users\afhac\appdata\local\programs\python\python39\lib\site-packages (from hyperlink>=17.1.1->Twisted==21.7.0->ctrader-open-api) (3.3)
Requirement already satisfied: setuptools in c:\users\afhac\appdata\local\programs\python\python39\lib\site-packages (from zope.interface>=4.4.2->Twisted==21.7.0->ctrader-open-api) (56.0.0)
Installing collected packages: ctrader-open-api
Successfully installed ctrader-open-api-0.9.0
PS C:\Users\afhac\source\OpenApiPy>
I tested on Windows 11.
Can you tell me on which OS you got that error? which version of Python and Pip you were using?
@amusleh
amusleh
10 Apr 2022, 09:43
Hi,
I check my own code with Lots set to 4, and the result was matching and it printed True.
I tried so find the issue on your code but as it's very long and complicated I gave up.
You can use this method to get volume splits/fragments:
/// <summary>
/// Splits the lots in volume units and returns an array of volumes
/// USe the returned array to execute orders for each volume
/// </summary>
/// <param name="lots">Volume in lots</param>
/// <param name="maxLotsPerSplit">Maximum lots per split/fragment</param>
/// <returns>double[]</returns>
private double[] GetVolumeSplits(double lots, double maxLotsPerSplit)
{
var modulus = lots % maxLotsPerSplit;
var numberOfFragments = Convert.ToInt32((lots - modulus) / maxLotsPerSplit);
if (modulus > 0) numberOfFragments++;
var lotsPerFragement = lots / numberOfFragments;
var unitsPerFragment = Symbol.QuantityToVolumeInUnits(lotsPerFragement);
var unitsPerFragementNormalized = Symbol.NormalizeVolumeInUnits(unitsPerFragment, RoundingMode.Up);
var volumes = new double[numberOfFragments];
for (var i = 0; i < numberOfFragments; i++)
{
volumes[i] = modulus > 0 && i == volumes.Length - 1
? unitsPerFragment - (unitsPerFragment + Symbol.VolumeInUnitsMin - unitsPerFragementNormalized)
: unitsPerFragementNormalized;
}
return volumes;
}
Once you calculated the x% volume, then pass it to this method with maximum lots per split/fragment, then it will split the volume and returns an array.
Use the array with a loop for executing orders.
@amusleh
amusleh
09 Apr 2022, 09:31
( Updated at: 09 Apr 2022, 09:34 )
Hi,
You can use this:
using System;
using System.Linq;
using cAlgo.API;
using cAlgo.API.Internals;
namespace NewcBot
{
[Robot(AccessRights = AccessRights.None)]
public class NewcBot : Robot
{
[Parameter("Max Lost Per Fragment", DefaultValue = 1)]
public double MaxLotsPerFragment { get; set; }
[Parameter("Lots", DefaultValue = 3.75)]
public double Lots { get; set; }
protected override void OnStart()
{
var modulus = Lots % MaxLotsPerFragment;
var numberOfFragments = Convert.ToInt32((Lots - modulus) / MaxLotsPerFragment);
if (modulus > 0)
{
numberOfFragments++;
}
var lotsPerFragement = Lots / numberOfFragments;
var unitsPerFragment = Symbol.QuantityToVolumeInUnits(lotsPerFragement);
var unitsPerFragementNormalized = Symbol.NormalizeVolumeInUnits(unitsPerFragment, RoundingMode.Up);
var volumes = new double[numberOfFragments];
for (var i = 0; i < numberOfFragments; i++)
{
volumes[i] = modulus > 0 && i == volumes.Length - 1
? unitsPerFragment - (unitsPerFragment + Symbol.VolumeInUnitsMin - unitsPerFragementNormalized)
: unitsPerFragementNormalized;
ExecuteMarketOrder(TradeType.Buy, SymbolName, volumes[i]);
}
// Check if the sum of fragments is equal to total volume (lots = 3.75)
Print(volumes.Sum() == Symbol.QuantityToVolumeInUnits(Lots));
}
}
}
It can give you an idea on how to do it, but the code definitely needs some improvements and optimizations.
You can use decimal instead of double but as the cTrader automate API is built around double it will make it much complicated.
For these kind of calculations double is not a good type, as it can cause rounding errors and non deterministic results on different CPUs.
@amusleh
amusleh
08 Apr 2022, 18:13
Hi,
Please stop creating multiple threads for same topic, continue with your first thread at: cTDN Forum - Ctrader should use standard file browsing
@amusleh
amusleh
12 Apr 2022, 10:16
Hi,
After you call execute market order method you should check result.IsSuccessful property before trying to access the Position property of result, example:
The above code is the right way for using result of an ExecuteMarketOrder non async call.
In case you just want to store a position on a collection when it opens you can use Positions.Opened event, example:
For ExecuteMarketOrderAsync you should use the callback delegate:
@amusleh