New Features in cTrader Automate API 3.7

Created at 04 Dec 2019, 14:52
How’s your experience with the cTrader Platform?
Your feedback is crucial to cTrader's development. Please take a few seconds to share your opinion and help us improve your trading experience. Thanks!
Spotware's avatar

Spotware

Joined 23.09.2013

New Features in cTrader Automate API 3.7
04 Dec 2019, 14:52


Historical Data API

cBots and indicators now have a new API to access historical price data.
Previously, historical data was accessible using MarketSeries interface which contains DataSeries for Open, High, Low, Close prices and more. Where each DataSeries is a collection of double numbers that can be accessible using bar index or you can be iterated using loops.

Old API DataSeries

MarketSeries.Open
MarketSeries.High
MarketSeries.Low
MarketSeries.Close
MarketSeries.TickVolume
MarketSeries.OpenTime

New API keeps the same DataSeries with a different names

Bars.OpenPrices
Bars.HighPrices
Bars.LowPrices
Bars.ClosePrices
Bars.TickVolumes
Bars.OpenTimes

Bar Type

Bars object adds more functionality. Now you can choose if you want to operate with a collection of prices or with a collection of bar objects. Bars itself is a collection of Bar objects.
You can get Bar by index or using LastBar property or Last() method to get bar from the end of the collection.
Example: print to log close prices for first and last bar on the chart.

var firstBar = Bars[0];
var lastBar = Bars.LastBar;
Print("First bar close {0}, last bar close {1}", firstBar.Close, lastBar.Close);

Output:
First bar close 1.23043, last bar close 1.10541

Or you can iterate through all of the bars.
Example: draw an arrow on each doji bar, where open equals to close.

foreach (var bar in Bars)
{
    if (bar.Open == bar.Close)
    {
        Chart.DrawIcon(bar.OpenTime.ToString(), ChartIconType.DownArrow, bar.OpenTime, bar.High, Color.Blue);
    }
}

Bar Events

You can subscribe to events for Bars:

Bars.Tick // Raised when a new tick arrives
Bars.BarOpened // Raised when last bar is closed and new bar is opened
Bars.HistoryLoaded // Raised when more history is loaded due to chart scroll on the left or due to API call
Bars.Reloaded // Raised when bars are refreshed due to reconnect

Ticks

Automate API adds Ticks to work with tick data.
Ticks is a collection of Tick objects with following properties

Tick.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

Load more history

For both Bars and Ticks you can load more history using LoadMoreHistory or LoadMoreHistoryAsync methods.
Below Is an example of loading 10 000 bars on the chart

Print("{0} bar on the chart. Loading 10 000 bars", Bars.Count);
while (Bars.Count < 10000)
{
    var loadedCount = Bars.LoadMoreHistory();
    Print("Loaded {0} bars", loadedCount);
    if (loadedCount == 0)
        break;
}
Print("Finished, total bars {0}", Bars.Count);

Output:
1143 bar on the chart. Loading 10 000 bars
Loaded 1141 bars
Loaded 1162 bars
Loaded 1129 bars
Loaded 1090 bars
Loaded 1126 bars
Loaded 1134 bars
Loaded 1134 bars
Loaded 1166 bars
Finished, total bars 10225

Bars and Ticks for other symbols and timeframes

cBots and indicators can request bars and ticks for other symbols and timeframes. MarketData contains synchronous and asynchronous methods to load this data

MarketData.GetBars
MarketData.GetBarsAsync
MarketData.GetTicks
MarketData.GetTicksAsync

Multi-Symbol Backtesting

Backtesting now allows to use and trade on other symbols than the symbol the cBot is running on. You can get desired Symbol using Symbol.GetSymbol or Symbols.GetSymbols methods.
To get events about price updates for received symbols use Symbol.Tick event.

Also, you can get historical data for other symbols during backtesting using MarketData.GetBars and MarketData.GetTicks methods.

The example below shows how to display changing prices on the chart for 4 symbols during visual backtesting.

public Symbol[] MySymbols;

protected override void OnStart()
{
    MySymbols = Symbols.GetSymbols("EURUSD", "GBPUSD", "USDJPY", "USDCHF");
    foreach (var symbol in MySymbols)
    {
        symbol.Tick += Symbol_Tick;
    }
}

private void Symbol_Tick(SymbolTickEventArgs obj)
{
    var sb = new StringBuilder();
    foreach (var symbol in MySymbols)
    {
        var textLine = string.Format("{0} {1} {2}", symbol.Name, symbol.Bid, symbol.Ask);
        sb.AppendLine(textLine);
    }
    Chart.DrawStaticText("symbols", sb.ToString(), VerticalAlignment.Top, HorizontalAlignment.Left, Chart.ColorSettings.ForegroundColor);
}

Clouds between indicator lines

Indicators now can add a semi-transparent cloud between two lines. Cloud can be easily added by adding Cloud attribute to your indicator.
It takes two line names as required parameters.
Cloud changes its color based on the color of the top line. If one line crosses another, cloud color changes. Line color is multiplied by the default opacity which is 0.2. You can change default behavior by setting following parameters in the Cloud attribute:

  • Opacity - opacity that will be applied to selected color
  • FirstColor - the color to use when first line is above the second line
  • SecondColor - the color to use when second line is above the first line

Below is an example of an indicator with fast Moving Average and slow Moving Average and a cloud between them

[Cloud("Fast MA", "Slow MA")]
[Indicator(IsOverlay = true, TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
public class MaCrossCloud : Indicator
{
    [Parameter("Fast MA Period", DefaultValue = 21)]
    public int FastMaPeriod { get; set; }

    [Parameter("Slow MA Period", DefaultValue = 50)]
    public int SlowMaPeriod { get; set; }

    [Output("Fast MA", LineColor = "#FF6666")]
    public IndicatorDataSeries FastMaResult { get; set; }

    [Output("Slow MA", LineColor = "#0071C1")]
    public IndicatorDataSeries SlowMaResult { get; set; }

    SimpleMovingAverage FastMa;
    SimpleMovingAverage SlowMa;


    protected override void Initialize()
    {
        FastMa = Indicators.SimpleMovingAverage(Bars.ClosePrices, FastMaPeriod);
        SlowMa = Indicators.SimpleMovingAverage(Bars.ClosePrices, SlowMaPeriod);
    }

    public override void Calculate(int index)
    {
        FastMaResult[index] = FastMa.Result[index];
        SlowMaResult[index] = SlowMa.Result[index];
    }
}

Set custom bar color

cBots or indicators can set a specific color for an individual bar on the chart. You can set fill color and outline color separately using Chart.SetBarFillColor and Chart.SetBarOutlineColor methods or change both colors together using Chart.SetBarColor.
Also, color for tick volumes can be changed using Chart.SetTickVolumeColor.

Bars will be changed till cBot or indicator is running on the chart. On stop, bar colors will be changed back to the user settings. If you want to reset bar color to users settings during the work of cBot/indicator, you can use Chart.ResetBarColor to reset individual bar or Chart.ResetBarColors to reset all bars. Same for tick volumes with Chart.ResetTickVolumeColor and Chart.ResetTickVolumeColors.

The example below shows how to set bar color to green if its close price is above Simple Moving Average and to red if it is below.

var sma = Indicators.SimpleMovingAverage(Bars.ClosePrices, 14);
for (var i = 0; i < Bars.Count; i++)
{
    var closePrice = Bars.ClosePrices[i];
    var smaValue = sma.Result[i];
    var barColor = closePrice > smaValue ? Color.Green : Color.Red;
    Chart.SetBarColor(i, barColor);
}

Changes in charts zoom API

As cTrader 3.7 introduces new smooth chart zooming, zoom values in API was changed.
Old Chart.Zoom property is deprecated. It used to have range of possible values from 0 to 5, which reflected old zoom levels on the user interface.
New Chart.ZoomLevel was added with values from 5 to 500 with a step of 5. These steps repeat new values on the user interface.

Obsoleted API

1. MarketSeries is obsolete. All methods that take a parameter of this type now have a new overload with Bars parameter instead of MarketSeries.
Affected methods to get indicator with a data source from another timeframe or symbol:

  • Indicators.GetIndicator() for custom indicators
  • And methods to get built-in indicators, like Indicators.Aroon() or Indicators.ParabolicSAR()

2. MarketData.GetSeries() is obsolete. It was replaced with MarketData.GetBars().


@Spotware
Replies

Waxy
05 Dec 2019, 05:05

RE:

Hello Spotware,

These are indeed great additions,

I see now that when I load an indicator that uses multiple MarketSeries (or now Bars) it takes much less than before, and this is great news, but at the start, it takes the same as before, so, I'd like to know if it's possible to improve or what's the best way now to load multiple series loading for indicators/bots during initialization, let's say I want to load 10 symbol bars, can I load these in parallel now?

 


@Waxy

ctid1574514
05 Dec 2019, 07:24

Multi Symbol Sample Trend cBot

The Sample Trend cBot trading 3 pairs.

I would have liked to have not used the switch and not declared all the indicators separately so it can scale to more pairs,  but it works trading multiple pairs on a back test

 

using System;
using System.Linq;
using System.Text;
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 MultSymbol : Robot
    {
        public Symbol[] MySymbols;

        [Parameter("Quantity (Lots)", Group = "Volume", DefaultValue = 1, MinValue = 0.01, Step = 0.01)]
        public double Quantity { get; set; }

        [Parameter("MA Type", Group = "Moving Average")]
        public MovingAverageType MAType { get; set; }

        [Parameter("Source", Group = "Moving Average")]
        public DataSeries SourceSeries { get; set; }

        [Parameter("Slow Periods", Group = "Moving Average", DefaultValue = 10)]
        public int SlowPeriods { get; set; }

        [Parameter("Fast Periods", Group = "Moving Average", DefaultValue = 5)]
        public int FastPeriods { get; set; }

        private MovingAverage slowMaEURUSD;
        private MovingAverage fastMaEURUSD;
        private MovingAverage slowMaUSDJPY;
        private MovingAverage fastMaUSDJPY;
        private MovingAverage slowMaGBPUSD;
        private MovingAverage fastMaGBPUSD;

        private const string label = "MultSymbolcBot";

        protected override void OnStart()
        {
            MySymbols = Symbols.GetSymbols("EURUSD", "USDJPY", "GBPUSD");
            foreach (var symbol in MySymbols)
            {
                symbol.Tick += Symbol_Tick;
            }

            Bars seriesEURUSD = MarketData.GetBars(TimeFrame, "EURUSD");
            Bars seriesUSDJPY = MarketData.GetBars(TimeFrame, "USDJPY");
            Bars seriesGBPUSD = MarketData.GetBars(TimeFrame, "GBPUSD");

            fastMaEURUSD = Indicators.MovingAverage(seriesEURUSD.ClosePrices, FastPeriods, MAType);
            slowMaEURUSD = Indicators.MovingAverage(seriesEURUSD.ClosePrices, SlowPeriods, MAType);

            fastMaUSDJPY = Indicators.MovingAverage(seriesUSDJPY.ClosePrices, FastPeriods, MAType);
            slowMaUSDJPY = Indicators.MovingAverage(seriesUSDJPY.ClosePrices, SlowPeriods, MAType);

            fastMaGBPUSD = Indicators.MovingAverage(seriesGBPUSD.ClosePrices, FastPeriods, MAType);
            slowMaGBPUSD = Indicators.MovingAverage(seriesGBPUSD.ClosePrices, SlowPeriods, MAType);
        }

        protected override void OnTick()
        {

        }

        protected override void OnStop()
        {

        }

        private void Symbol_Tick(SymbolTickEventArgs obj)
        {
            foreach (var symbol in MySymbols)
            {
                switch (symbol.Name)
                {
                    case "EURUSD":
                        SymbolTrade(symbol, fastMaEURUSD, slowMaEURUSD);
                        break;
                    case "USDJPY":
                        SymbolTrade(symbol, fastMaUSDJPY, slowMaUSDJPY);
                        break;
                    case "GBPUSD":
                        SymbolTrade(symbol, fastMaGBPUSD, slowMaGBPUSD);
                        break;
                }
            }
        }

        private double VolumeInUnits
        {
            get { return Symbol.QuantityToVolumeInUnits(Quantity); }
        }

        private void SymbolTrade(Symbol SymbolName, MovingAverage MaNameFast, MovingAverage MaNameSlow)
        {
            var longPosition = Positions.Find(label, SymbolName.Name, TradeType.Buy);
            var shortPosition = Positions.Find(label, SymbolName.Name, TradeType.Sell);

            var currentSlowMa = MaNameSlow.Result.Last(0);
            var currentFastMa = MaNameFast.Result.Last(0);
            var previousSlowMa = MaNameSlow.Result.Last(1);
            var previousFastMa = MaNameFast.Result.Last(1);

            if (previousSlowMa > previousFastMa && currentSlowMa <= currentFastMa && longPosition == null)
            {
                if (shortPosition != null)
                    ClosePosition(shortPosition);
                ExecuteMarketOrder(TradeType.Buy, SymbolName.Name, VolumeInUnits, label);
            }
            else if (previousSlowMa < previousFastMa && currentSlowMa >= currentFastMa && shortPosition == null)
            {
                if (longPosition != null)
                    ClosePosition(longPosition);
                ExecuteMarketOrder(TradeType.Sell, SymbolName.Name, VolumeInUnits, label);
            }
        }
    }
}

 


@ctid1574514

PanagiotisCharalampous
05 Dec 2019, 10:26

RE: RE:

Waxy said:

Hello Spotware,

These are indeed great additions,

I see now that when I load an indicator that uses multiple MarketSeries (or now Bars) it takes much less than before, and this is great news, but at the start, it takes the same as before, so, I'd like to know if it's possible to improve or what's the best way now to load multiple series loading for indicators/bots during initialization, let's say I want to load 10 symbol bars, can I load these in parallel now?

 

Hi Xavier,

You can use MarketData.GetBarsAsync() and MarketData.GetTicksAsync() to get data asynchronously.

Best Regards,

Panagiotis 

Join us on Telegram

 


@PanagiotisCharalampous

Waxy
05 Dec 2019, 16:39

RE: RE: RE:

Hello Panagiotis,

I'm trying out the following code,

using System.Collections.Generic;
using cAlgo.API;

namespace cAlgo
{
    [Indicator(IsOverlay = false, TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
    public class NewIndicator : Indicator
    {
        private readonly List<Bars> _bars = new List<Bars>();
        private readonly string[] _mySymbols = {"EURUSD","GBPUSD","EURJPY","USDJPY","AUDUSD","USDCHF","GBPJPY","USDCAD","EURGBP","EURCHF"};

        protected override void Initialize()
        {
            Print("Initializing");

            foreach (var symbol in _mySymbols)
            {
                Print(string.Format("Loading Symbol {0}", symbol));
                MarketData.GetBarsAsync(TimeFrame.Hour, symbol, bar =>
                {
                    _bars.Add(bar);
                    Print(string.Format("{0} Loaded, Bars: {1}", bar.SymbolName, bar.Count));
                });
            }

            Print("End Initializing");
        }

        public override void Calculate(int index) { }
    }
}

I get the responses in the log in this order, doesn't seem to work properly to me, is this correct, or I'm I doing something wrong, is this the best way to do it? It takes about 16 seconds to load them all (don't get me wrong it's a big improvement), could it load faster?

05/12/2019 14:20:04.782 | Initializing
05/12/2019 14:20:04.782 | Loading Symbol EURUSD
05/12/2019 14:20:04.797 | Loading Symbol GBPUSD
05/12/2019 14:20:04.797 | Loading Symbol EURJPY
05/12/2019 14:20:05.219 | Loading Symbol USDJPY
05/12/2019 14:20:05.235 | Loading Symbol AUDUSD
05/12/2019 14:20:05.657 | Loading Symbol USDCHF
05/12/2019 14:20:06.641 | Loading Symbol GBPJPY
05/12/2019 14:20:07.078 | Loading Symbol USDCAD
05/12/2019 14:20:07.110 | Loading Symbol EURGBP
05/12/2019 14:20:07.485 | Loading Symbol EURCHF
05/12/2019 14:20:07.953 | Loading Symbol AUDJPY
05/12/2019 14:20:08.344 | Loading Symbol NZDUSD
05/12/2019 14:20:08.391 | Loading Symbol CHFJPY
05/12/2019 14:20:08.813 | Loading Symbol EURAUD
05/12/2019 14:20:09.344 | Loading Symbol CADJPY
05/12/2019 14:20:09.782 | Loading Symbol GBPAUD
05/12/2019 14:20:10.250 | Loading Symbol EURCAD
05/12/2019 14:20:10.657 | Loading Symbol AUDCAD
05/12/2019 14:20:11.203 | Loading Symbol GBPCAD
05/12/2019 14:20:11.813 | Loading Symbol USDNOK
05/12/2019 14:20:13.063 | Loading Symbol AUDCHF
05/12/2019 14:20:13.672 | Loading Symbol USDMXN
05/12/2019 14:20:15.094 | Loading Symbol GBPNZD
05/12/2019 14:20:15.110 | Loading Symbol CADCHF
05/12/2019 14:20:15.719 | Loading Symbol USDSEK
05/12/2019 14:20:16.969 | Loading Symbol GBPCHF
05/12/2019 14:20:17.578 | Loading Symbol EURRUB
05/12/2019 14:20:19.453 | Loading Symbol NZDCHF
05/12/2019 14:20:20.078 | Loading Symbol NZDCAD
05/12/2019 14:20:20.703 | Loading Symbol AUDNZD
05/12/2019 14:20:20.735 | End Initializing
05/12/2019 14:20:20.735 | EURUSD Loaded, Bars: 2323
05/12/2019 14:20:20.735 | GBPUSD Loaded, Bars: 2013
05/12/2019 14:20:20.735 | EURJPY Loaded, Bars: 2013
05/12/2019 14:20:20.735 | USDJPY Loaded, Bars: 1650
05/12/2019 14:20:20.750 | AUDUSD Loaded, Bars: 2013
05/12/2019 14:20:20.750 | USDCHF Loaded, Bars: 2013
05/12/2019 14:20:20.750 | GBPJPY Loaded, Bars: 2013
05/12/2019 14:20:20.750 | USDCAD Loaded, Bars: 2013
05/12/2019 14:20:20.750 | EURGBP Loaded, Bars: 2013
05/12/2019 14:20:20.750 | EURCHF Loaded, Bars: 2013
05/12/2019 14:20:20.750 | AUDJPY Loaded, Bars: 2013
05/12/2019 14:20:20.750 | NZDUSD Loaded, Bars: 2013
05/12/2019 14:20:20.750 | CHFJPY Loaded, Bars: 2013
05/12/2019 14:20:20.750 | EURAUD Loaded, Bars: 2013
05/12/2019 14:20:20.750 | CADJPY Loaded, Bars: 2013
05/12/2019 14:20:20.750 | GBPAUD Loaded, Bars: 2013
05/12/2019 14:20:20.750 | EURCAD Loaded, Bars: 2013
05/12/2019 14:20:20.750 | AUDCAD Loaded, Bars: 2013
05/12/2019 14:20:20.750 | GBPCAD Loaded, Bars: 2013
05/12/2019 14:20:20.750 | USDNOK Loaded, Bars: 1170
05/12/2019 14:20:20.750 | AUDCHF Loaded, Bars: 2013
05/12/2019 14:20:20.750 | USDMXN Loaded, Bars: 1170
05/12/2019 14:20:20.750 | GBPNZD Loaded, Bars: 2013
05/12/2019 14:20:20.750 | CADCHF Loaded, Bars: 2013
05/12/2019 14:20:20.750 | USDSEK Loaded, Bars: 1170
05/12/2019 14:20:20.750 | GBPCHF Loaded, Bars: 2013
05/12/2019 14:20:20.750 | EURRUB Loaded, Bars: 1167
05/12/2019 14:20:20.750 | NZDCHF Loaded, Bars: 2013
05/12/2019 14:20:20.985 | NZDCAD Loaded, Bars: 2012
05/12/2019 14:20:21.203 | AUDNZD Loaded, Bars: 2013
 

PanagiotisCharalampous said:

Waxy said:

Hello Spotware,

These are indeed great additions,

I see now that when I load an indicator that uses multiple MarketSeries (or now Bars) it takes much less than before, and this is great news, but at the start, it takes the same as before, so, I'd like to know if it's possible to improve or what's the best way now to load multiple series loading for indicators/bots during initialization, let's say I want to load 10 symbol bars, can I load these in parallel now?

 

Hi Xavier,

You can use MarketData.GetBarsAsync() and MarketData.GetTicksAsync() to get data asynchronously.

Best Regards,

Panagiotis 

Join us on Telegram

 

 


@Waxy

PanagiotisCharalampous
05 Dec 2019, 16:55 ( Updated at: 21 Dec 2023, 09:21 )

Hi Xavier R,

1) As a good practice please try to create new threads for such discussions. It will be easier for future searches by other users.

2) I am not sure what is the issue. The 16 seconds? Note that this data needs be downloaded from the server so you should also take that into consideration. In my case, bars are loaded almost instantly. See below

Best Regards,

Panagiotis 

Join us on Telegram

 


@PanagiotisCharalampous

Waxy
05 Dec 2019, 18:19

RE:

What I mean is that it takes me 10-15 seconds to load these symbols, not almost instantly, I'm using 30mbps.

Only after the first load, any refresh of the bot/indicator and the bars load instantly afterward (which again, it's great news).

Also, I think a good option would be to have an overload where we can specify how many bars to load, because many times a thousand daily bars is not really needed, is it possible?

And I'm since this is part of the update I thought it would be correct to ask about it in this thread, I'll leave it here and if needed I'll open a new thread, sorry about that.

Thanks for your support


@Waxy

... Deleted by UFO ...

w.b.z
06 Feb 2020, 19:48

3.7 changed something in code, now half of my Algo`s dont work anymore..can anyone tell me what to do?


@w.b.z

mparama
10 Feb 2020, 03:15 ( Updated at: 21 Dec 2023, 09:21 )

RE: 3.7 changed something in code, now half of my Algo`s dont work anymore..can anyone tell me what to do?

w.b.z said:

I got the same problem with optimization using multi-timeframe.

Backtest is ok

Trading is ok

when I try to optimize I get  "Crashed in OnTick with NullReferenceException: Object reference not set to an instance of an object" and I found that the problem is related to the New API with Multi-TimeFrames,:

I replaced the old MarketSeries (everything was working fine) with the New API line guide (Optimization not working)


@mparama

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 properties

Tick.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
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:

 

public Bars hour;

 hour = MarketData.GetBars(TimeFrame.Hour);

public override void Calculate(int index)
        {
              int i_hour = hour.OpenTime.GetIndexByTime(MarketSeries.OpenTime[index]);
          //  int i_hour = hour.OpenTime.GetIndexByTime(Bars.OpenTimes[index]);

....

 

I cannot find anywhere how to replace

hour.OpenTime.GetIndexByTime(MarketSeries.OpenTime[index]);

I tried just adding

Bars.OpenTimes[index]

instead of

MarketSeries.OpenTime[index]

but still getting an error message, and the problem is the 

OpenTime

I just cannot find anywhere what to replace it with?

 

I also have:

_hour[index] = hour.Open[i_hour];

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

PanagiotisCharalampous
20 Feb 2020, 14:19 ( Updated at: 21 Dec 2023, 09:21 )

Hi Jan,

I am not sure how clearer we can make the messages. You get three messages explaining to you exactly what do you need to do.

So as per the messages above

 int i_hour = hour.OpenTime.GetIndexByTime(MarketSeries.OpenTime[index]);

should become

int i_hour = hour.OpenTimes.GetIndexByTime(Bars.OpenTimes[index]);

Is it not understood from the message 

Error CS0618: 'cAlgo.API.Internals.MarketSeries.OpenTime' is obsolete: 'Use Bars.OpenTimes instead'

that MarketSeries.OpenTime should become Bars.OpenTimes?

Also if you use 

  var i = MarketSeries.Open[0];

You will get

 

which I think it describes clearly that it should be changed to

var i = Bars.OpenPrices[0];

as a result

_hour[index] = hour.Open[i_hour]

should become

_hour[index] = hour.OpenPrices[i_hour]

Best Regards,

Panagiotis 

Join us on Telegram

 


@PanagiotisCharalampous

... Deleted by UFO ...

jani
09 Mar 2020, 00:05 ( Updated at: 21 Dec 2023, 09:21 )

Problems with substitutions

I'm still having issues with substituting new API definitions. I tried to do exactly as the warning messages direct, but still unable to find the correct format and getting error messages.

I have:

using System;
using cAlgo.API;
using cAlgo.API.Internals;
using cAlgo.API.Indicators;
using cAlgo.Indicators;


namespace cAlgo.Indicators
{

    [Indicator(IsOverlay = true, TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
    public class HighestHighLowestLow2 : Indicator
    {

        [Parameter(" Period", DefaultValue = 10, MinValue = 1)]
        public int Period { get; set; }

        [Parameter(" Timeframe")]
        public TimeFrame AnotherTimeFrame { get; set; }

        [Output("Close Up", LineColor = "Red")]
        public IndicatorDataSeries CloseUp { get; set; }

        [Output("High", LineColor = "Pink")]
        public IndicatorDataSeries High { get; set; }

        [Output("Close Down", LineColor = "Blue")]
        public IndicatorDataSeries CloseDown { get; set; }

        [Output("Low", LineColor = "Aqua")]
        public IndicatorDataSeries Low { get; set; }

        public MarketSeries dataseries;
        // public Bars dataseries;

        protected override void Initialize()
        {

            dataseries = MarketData.GetSeries(Symbol, AnotherTimeFrame);
            // dataseries = MarketData.GetBars(Symbol, AnotherTimeFrame);
        }

        public override void Calculate(int index)
        {
            // Top[index] = MarketSeries.High.Maximum(PeriodsHigh);
            //Bottom[index] = MarketSeries.Low.Minimum(PeriodsLow);

            High[index] = dataseries.High.Maximum(Period);
            //High[index] = dataseries.Bars.HighPrices.Maximum(Period);

            CloseUp[index] = dataseries.Close.Maximum(Period);
            CloseDown[index] = dataseries.Close.Minimum(Period);
            Low[index] = dataseries.Low.Minimum(Period);
        }
    }
}

I'm getting warnings:

For example if I change 

public MarketSeries dataseries;

to

 public Bars dataseries;

as the instruction says, I get an error:

 

Sorry to trouble with a similar issue, but I believe I'm not alone here with these 3.7 API substitution troubles...?

 


@jani

PanagiotisCharalampous
09 Mar 2020, 09:16

Hi Jani,

You do the substitution but you do not change the line below to

 dataseries = MarketData.GetSeries(Symbol, AnotherTimeFrame);

to 

dataseries = MarketData.GetBars(AnotherTimeFrame, Symbol.Name);

Here is the updated code

using System;
using cAlgo.API;
using cAlgo.API.Internals;
using cAlgo.API.Indicators;
using cAlgo.Indicators;


namespace cAlgo.Indicators
{

    [Indicator(IsOverlay = true, TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
    public class HighestHighLowestLow2 : Indicator
    {

        [Parameter(" Period", DefaultValue = 10, MinValue = 1)]
        public int Period { get; set; }

        [Parameter(" Timeframe")]
        public TimeFrame AnotherTimeFrame { get; set; }

        [Output("Close Up", LineColor = "Red")]
        public IndicatorDataSeries CloseUp { get; set; }

        [Output("High", LineColor = "Pink")]
        public IndicatorDataSeries High { get; set; }

        [Output("Close Down", LineColor = "Blue")]
        public IndicatorDataSeries CloseDown { get; set; }

        [Output("Low", LineColor = "Aqua")]
        public IndicatorDataSeries Low { get; set; }

        public Bars dataseries;
        // public Bars dataseries;

        protected override void Initialize()
        {

            dataseries = MarketData.GetBars(AnotherTimeFrame, Symbol.Name);
            // dataseries = MarketData.GetBars(Symbol, AnotherTimeFrame);
        }

        public override void Calculate(int index)
        {
            // Top[index] = MarketSeries.High.Maximum(PeriodsHigh);
            //Bottom[index] = MarketSeries.Low.Minimum(PeriodsLow);

            High[index] = dataseries.HighPrices.Maximum(Period);
            //High[index] = dataseries.Bars.HighPrices.Maximum(Period);

            CloseUp[index] = dataseries.ClosePrices.Maximum(Period);
            CloseDown[index] = dataseries.ClosePrices.Minimum(Period);
            Low[index] = dataseries.LowPrices.Minimum(Period);
        }
    }
}

Best Regards,

Panagiotis 

Join us on Telegram

 


@PanagiotisCharalampous

jani
09 Mar 2020, 10:54

RE:

Thank you Panagiotis,

This was very helpful!


@jani

... Deleted by UFO ...

justinpor119
28 May 2020, 13:31

One can now add custom UI elements and modify chart controls in Automate API for cBots and indicators. Available panels with different layouts and controls feature a variety of options upsers portal


@justinpor119

alfredwilliam0809
28 May 2020, 15:34

  • FXStreet Economic Calendar.
  • Multi-Symbol Backtesting for cBots.
  • New Chart Zoom.
  • Freehand Drawing Tool.
  • Detached Chart Containers.
  • Hide Sensitive Information.
  • New Historical Data API.
  • Clouds Between Indicator Lines.

chatcpe
07 Jul 2020, 10:59

Example multi symbol

namespace cAlgo
{
    [Robot(TimeZone = TimeZones.UTC, AccessRights = AccessRights.FullAccess)]
    public class EMA_2Cross_1Trend_RR : Robot
    {
        [Parameter("Fix Vol Trade", DefaultValue = true, Group = "Trade")]
        public bool FixVolTrade { get; set; }

        [Parameter("PerStart", DefaultValue = 1, Group = "Trade", MinValue = 1)]
        public int PerStart { get; set; }

        [Parameter("TradeWay", Group = "Trade", DefaultValue = TradeOnlyWay.Both)]
        public TradeOnlyWay WantTradeWay { get; set; }

        [Parameter("TP", Group = "Trade", DefaultValue = 50, MinValue = 1)]
        public int TP { get; set; }

        [Parameter("SL", Group = "Trade", DefaultValue = 25, MinValue = 1)]
        public int SL { get; set; }

        [Parameter("MaxOpen", Group = "Trade", DefaultValue = 1, MinValue = 1)]
        public int MaxOpen { get; set; }

        [Parameter("SymBol To Trade", Group = "Trade", DefaultValue = "AUDCAD,AUDCHF,AUDJPY,AUDNZD,AUDSGD,AUDUSD,CADCHF,CADJPY,CHFJPY,CHFSGD,EURAUD,EURCAD,EURCHF,EURGBP,EURJPY,EURNZD,EURSGD,EURUSD,GBPAUD,GBPCAD,GBPCHF,GBPJPY,GBPNZD,GBPSGD,GBPUSD,NZDCAD,NZDCHF,NZDJPY,NZDUSD,SGDJPY,USDCAD,USDCHF,USDJPY,USDSGD")]
        public string SymBolToTrade { get; set; }

        [Parameter("Strategies name", Group = "Trade", DefaultValue = "EMA_2Cross_1Trend_RR")]
        public string StrategiesName { get; set; }


        #region EMA


        [Parameter("EMA 1 Source", Group = "EMA")]
        public DataSeries EMA1Source { get; set; }

        [Parameter("EMA 1 Periods", Group = "EMA", DefaultValue = 9)]
        public int EMA1_Period { get; set; }

        [Parameter("EMA 2 Source", Group = "EMA")]
        public DataSeries EMA2Source { get; set; }

        [Parameter("EMA 2 Periods", Group = "EMA", DefaultValue = 21)]
        public int EMA2_Period { get; set; }

        [Parameter("EMA 2 Source", Group = "EMA")]
        public DataSeries EMA3Source { get; set; }

        [Parameter("EMA 3 Periods", Group = "EMA", DefaultValue = 200)]
        public int EMA3_Period { get; set; }


        #endregion

        List<Symbol> lsSymbol = new List<Symbol>();
        Dictionary<Symbol, Bars> dicSymbolBar = new Dictionary<Symbol, Bars>();
        Dictionary<Symbol, ExponentialMovingAverage> dicEMA1 = new Dictionary<Symbol, ExponentialMovingAverage>();
        Dictionary<Symbol, ExponentialMovingAverage> dicEMA2 = new Dictionary<Symbol, ExponentialMovingAverage>();
        Dictionary<Symbol, ExponentialMovingAverage> dicEMA3 = new Dictionary<Symbol, ExponentialMovingAverage>();

        List<TradeLog> _tradeLogs = new List<TradeLog>();
        double StartBalance = 0;

        protected override void OnStart()
        {
            Print("Start OnStart");

            StartBalance = Account.Balance;

            Positions.Opened += PositionsOnOpened;
            Positions.Closed += PositionsOnClosed;

            LoadSymbolsDataAndIndi();

            Print("End OnStart");
        }

        private void LoadSymbolsDataAndIndi()
        {
            try
            {
                //แยกคู่ที่ต้องการเทรดด้วย ,
                var AllSymbol = SymBolToTrade.Split(',').ToList();

                //List<Task> lsTask = new List<Task>();
                foreach (var sSymbol in AllSymbol)
                {
                    //Task aTask = new Task(() =>
                    //{
                    var bar = MarketData.GetBars(TimeFrame, sSymbol);
                    var aSymbolBars = MarketData.GetBars(TimeFrame, sSymbol);
                    var aSymbol = Symbols.GetSymbol(sSymbol);

                    lsSymbol.Add(aSymbol);
                    dicSymbolBar.Add(aSymbol, aSymbolBars);
                    dicEMA1.Add(aSymbol, Indicators.ExponentialMovingAverage(aSymbolBars.ClosePrices, EMA1_Period));
                    dicEMA2.Add(aSymbol, Indicators.ExponentialMovingAverage(aSymbolBars.ClosePrices, EMA2_Period));
                    dicEMA3.Add(aSymbol, Indicators.ExponentialMovingAverage(aSymbolBars.ClosePrices, EMA3_Period));

                    Print("Finished get data >> " + sSymbol);
                    //});
                    //lsTask.Add(aTask);
                    //aTask.Start();
                }
                //Task.WaitAll(lsTask.ToArray());
            } catch (Exception ex)
            {
                Print("ERROR LoadSymbolsDataAndIndi : " + ex.Message);
            }
        }

protected override void OnBar()
        {
            try
            {
                List<Task> lsTask = new List<Task>();
                foreach (var symbol in lsSymbol)
                {
                    //แตก thread แยกตามคู่เงิน
                    Task aTask = new Task(() =>
                    {
                        //ema1 ตัด ema2 *ลง*  && ย้อนหลังไปสองแท่งที่ยังไม่ตัดลง EMA1 ยังต้อง*มากกว่า* 2 ด้วย ไม่งั้นมันจะเข้าออเดอร์ทุกๆแท่งเอาได้  *หรือเราจะไปเช็คว่ามีออเดอร์เปิดแล้วก็ไม่ให้เปิดดีกว่านะ
                        if (dicEMA1.Where(x=>x.Key == symbol).First().Value.Result.Last(1) <= dicEMA2.Where(x => x.Key == symbol).First().Value.Result.Last(1) && dicEMA1.Where(x => x.Key == symbol).First().Value.Result.Last(2) > dicEMA2.Where(x => x.Key == symbol).First().Value.Result.Last(2))
                        {
                            //EMA 1 & 2 ต้องอยู่*ใต้* 3 ด้วย
                            if (dicEMA1.Where(x=>x.Key == symbol).First().Value.Result.Last(1) <= dicEMA3.Where(x=>x.Key == symbol).First().Value.Result.Last(1) && dicEMA2.Where(x=>x.Key == symbol).First().Value.Result.Last(1) <= dicEMA3.Where(x=>x.Key == symbol).First().Value.Result.Last(1))
                            {
                                //*ยังไม่เช็คว่ามีออเดอร์เปิดอยู่แล้ว เปิดเพิ่มได้ กรณียังไม่ tp หรือ SL แต่มันวกมาตัดขึ้น-ลงเพิ่มอีกก็เป็นไปได้
                                //เช็คกับการตั้งค่าว่าให้เล่นแต่ขาไหน จะเข้า *sell* แต่ถ้าจะเล่นแต่ขา *buy* เราก็จะไม่เปิด
                                if (WantTradeWay != TradeOnlyWay.Buy)
                                {
                                    //เช็คกรณีว่าเปิดไปแล้วกี่ไม้ และจะไม่ให้เปิดอีก เช็คเฉพาะขานั้นด้วย เพราะมีสิทธิ์มีสองขาเปิดพร้อมกันอยู่
                                    if (Positions.Where(x => x.TradeType == TradeType.Sell).Count() >= MaxOpen)
                                    {
                                        return;
                                    }
                                    ExecuteMarketOrder(TradeType.Sell, SymbolName, Symbol.NormalizeVolumeInUnits((FixVolTrade ? StartBalance : Account.Balance) * PerStart), StrategiesName, SL, TP, "");
                                }
                            }
                        }.......


@chatcpe

... Deleted by UFO ...

... Deleted by UFO ...

... Deleted by UFO ...