Topics
Forum Topics not found
Replies
amusleh
09 Apr 2021, 14:07
Hi,
It calls the OnTick event whenever a new tick arrives and it has precedence over invoking events, that's how it works on real live market and the back tester simulates the same condition.
There is an issue while back testing in slower speed and it should not invoke PendingOrders.Filled event before calling OnTick, we will investigate it and if there was any bug it will be fixed in future releases.
@amusleh
amusleh
08 Apr 2021, 15:44
Hi,
This sample might help you:
using cAlgo.API;
namespace cAlgo
{
/// <summary>
/// This sample shows how to use Thickness for defining a chart control margin
/// </summary>
[Indicator(IsOverlay = true, TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
public class ThicknessSample : Indicator
{
protected override void Initialize()
{
var stackPanel = new StackPanel
{
HorizontalAlignment = HorizontalAlignment.Center,
VerticalAlignment = VerticalAlignment.Center,
BackgroundColor = Color.Gold,
Opacity = 0.6
};
var rectangle = new Rectangle
{
StrokeColor = Color.Blue,
FillColor = Color.Red,
StrokeThickness = 2,
Margin = new Thickness(10, 5, 10, 5),
Width = 300,
Height = 100,
};
stackPanel.AddChild(rectangle);
Chart.AddControl(stackPanel);
}
public override void Calculate(int index)
{
}
}
}
MArgin property type is Thickness.
@amusleh
amusleh
08 Apr 2021, 11:14
( Updated at: 08 Apr 2021, 11:50 )
Hi,
Whenever you change a parameter of an indicator, load more data, or get disconnected and re-connected cTrader re-initializes the indicator and your indicator have to re-calculate everything from start.
The way cTrader works is much better than other platforms, because it doesn't force developers to manage events and do all the work of updating the indicator outputs for new data or re-adjusting the indicator already calculated data, but yes it consumes more processing power.
To solve the CPU processing power consumption issue, you can write your indicator calculated outputs data on a file and then when indicator initializes check if the file exist, if there is a cache file for indicator data fill the outputs by loading the file data instead of re-calculating the data and escape the bars until you reach the bars that aren't in your file.
@amusleh
amusleh
07 Apr 2021, 13:17
Hi,
OnBar/Tick methods are called based on current chart symbol and time frame, if you want to receive on bar/tick events of other timeframes or symbols yopu have to first get that symbol/timeframe Bars object by calling the MarketData.GetBars method and passing the time frame and symbol name.
After you got the Bars then you can subscribe to its BarOpened and Tick events:
using cAlgo.API;
using System;
namespace cAlgo
{
[Indicator(IsOverlay = false, TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
public class BarsSample : Indicator
{
private TextBlock _barTicksNumberTextBlock, _barsStateTextBlock;
[Output("Range", LineColor = "RoyalBlue")]
public IndicatorDataSeries Range { get; set; }
[Output("Body", LineColor = "Yellow")]
public IndicatorDataSeries Body { get; set; }
protected override void Initialize()
{
// Bars events
Bars.BarOpened += Bars_BarOpened;
Bars.Tick += Bars_Tick;
Bars.HistoryLoaded += Bars_HistoryLoaded;
Bars.Reloaded += Bars_Reloaded;
var grid = new Grid(2, 2)
{
BackgroundColor = Color.DarkGoldenrod,
HorizontalAlignment = HorizontalAlignment.Right,
VerticalAlignment = VerticalAlignment.Top,
Opacity = 0.5
};
grid.AddChild(new TextBlock
{
Text = "Bar Ticks #",
Margin = 5
}, 0, 0);
_barTicksNumberTextBlock = new TextBlock
{
Text = "0",
Margin = 5
};
grid.AddChild(_barTicksNumberTextBlock, 0, 1);
grid.AddChild(new TextBlock
{
Text = "Bars State",
Margin = 5
}, 1, 0);
_barsStateTextBlock = new TextBlock
{
Margin = 5
};
grid.AddChild(_barsStateTextBlock, 1, 1);
IndicatorArea.AddControl(grid);
}
private void Bars_Reloaded(BarsHistoryLoadedEventArgs obj)
{
_barsStateTextBlock.Text = "Reloaded";
}
private void Bars_HistoryLoaded(BarsHistoryLoadedEventArgs obj)
{
_barsStateTextBlock.Text = "History Loaded";
}
private void Bars_Tick(BarsTickEventArgs obj)
{
_barTicksNumberTextBlock.Text = Bars.TickVolumes.LastValue.ToString();
}
private void Bars_BarOpened(BarOpenedEventArgs obj)
{
_barsStateTextBlock.Text = "New Bar Opened";
}
public override void Calculate(int index)
{
Range[index] = Bars.HighPrices[index] - Bars.LowPrices[index];
Body[index] = Math.Abs(Bars.ClosePrices[index] - Bars.OpenPrices[index]);
}
}
}
Getting Bars of another timeframe/symbol:
using cAlgo.API;
using cAlgo.API.Internals;
namespace cAlgo
{
[Indicator(IsOverlay = true, TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
public class MarketDataSample : Indicator
{
private Bars _bars;
private Ticks _ticks;
private MarketDepth _marketDepth;
[Parameter("Use Current Symbol", DefaultValue = true)]
public bool UseCurrentSymbol { get; set; }
[Parameter("Other Symbol Name", DefaultValue = "GBPUSD")]
public string OtherSymbolName { get; set; }
[Parameter("Use Current TimeFrame", DefaultValue = true)]
public bool UseCurrentTimeFrame { get; set; }
[Parameter("Other TimeFrame", DefaultValue = "Daily")]
public TimeFrame OtherTimeFrame { get; set; }
protected override void Initialize()
{
var symbol = UseCurrentSymbol ? Symbol : Symbols.GetSymbol(OtherSymbolName);
var timeframe = UseCurrentTimeFrame ? TimeFrame : OtherTimeFrame;
// You can use GetBarsAsync instead of GetBars
_bars = MarketData.GetBars(timeframe, symbol.Name);
// You can use GetTicksAsync instead of GetTicks
_ticks = MarketData.GetTicks(symbol.Name);
_marketDepth = MarketData.GetMarketDepth(symbol.Name);
}
public override void Calculate(int index)
{
}
}
}
@amusleh
amusleh
07 Apr 2021, 11:16
Hi,
You should do it like this:
using cAlgo.API;
namespace cAlgo
{
[Indicator(IsOverlay = false, TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
public class NewIndicator : Indicator
{
[Parameter("Period", DefaultValue = 10)]
public int Period { get; set; }
[Output("Main")]
public IndicatorDataSeries Result { get; set; }
protected override void Initialize()
{
}
public override void Calculate(int index)
{
var highest = Bars.ClosePrices.Maximum(Period);
Result[index] = (highest - Bars.LowPrices[index]) / highest * 100;
}
}
}
Please learn C# basics and read cTrader Automate API references before trying to develop a cBot/indicator for cTrader.
@amusleh
amusleh
07 Apr 2021, 11:10
RE: RE:
animate44x said:
amusleh said:
Hi,
Not sure what do you mean by command, but you can access other time frames data from current or other symbols, here is a sample:
Once you got the bars then you can access the open/high/clow/close prices.
Thank you, that is what I was looking for. Could not find how to specify timeframe with the bars syntax.
The first parameter of MarketData.GetBars method is time frame, its in the sample if you check the code.
@amusleh
amusleh
07 Apr 2021, 11:08
Hi,
Please use my sample code for adding time range on your cBot, your cBot code is not correct and it even doesn't compile.
Next time you post code use the editor code snippet feature.
I recommend you to study C# basic and API references.
I consider this thread closed, we can't develop your cBot for you, all you need is already posted.
@amusleh
amusleh
07 Apr 2021, 11:03
Hi,
The methods works the way I explained on my previous post, just tested with this sample:
using cAlgo.API;
using cAlgo.API.Indicators;
namespace cAlgo
{
[Indicator(IsOverlay = false, TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
public class HasCrossedSample : Indicator
{
private SimpleMovingAverage _fastMa, _slowMa;
[Parameter("Type", DefaultValue = CrossType.Above)]
public CrossType CrossType { get; set; }
[Parameter("Period", DefaultValue = 10)]
public int Period { get; set; }
[Output("Fast MA", LineColor = "Red", Thickness = 1)]
public IndicatorDataSeries FastMa { get; set; }
[Output("Slow MA", LineColor = "Yellow", Thickness = 2)]
public IndicatorDataSeries SlowMa { get; set; }
protected override void Initialize()
{
_fastMa = Indicators.SimpleMovingAverage(Bars.ClosePrices, 9);
_slowMa = Indicators.SimpleMovingAverage(Bars.ClosePrices, 20);
}
public override void Calculate(int index)
{
FastMa[index] = _fastMa.Result[index];
SlowMa[index] = _slowMa.Result[index];
if (!IsLastBar) return;
Chart.DrawVerticalLine("line", index - Period, Color.Red, 2);
if (CrossType == CrossType.Above && FastMa.HasCrossedAbove(SlowMa, Period)) Print("Crossed");
else if (CrossType == CrossType.Below && FastMa.HasCrossedBelow(SlowMa, Period)) Print("Crossed");
}
}
public enum CrossType
{
Above,
Below
}
}
The sample indicator will draw a vertical line on period start, and then if fast MA crossed above/below slow MA it will print "Crossed" on log.
A cross must happen during the period values.
@amusleh
amusleh
06 Apr 2021, 15:04
Hi,
The methods check if there was any cross in x last periods, if there was any it returns true otherwise it returns false.
If you use HasCrossedAbove with 10 as period, then it checks if is the crossing series has crossed at least one time the crossed series upward in last 10 values or not, if it did then the method returns true otherwise it returns false.
Same for HasCrossedBelow, except it checks for downward cross.
An up cross happens if a value inside crossing series goes above//equal to crossed series value and previous value of crossing series was below crossed series value.
A down cross happens if a value inside crossing series goes below//equal to crossed series value and previous value of crossing series was above crossed series value.
@amusleh
amusleh
06 Apr 2021, 10:47
Hi,
This sample cBot might help you:
using cAlgo.API;
using System;
using System.Globalization;
namespace cAlgo.Robots
{
[Robot(TimeZone = TimeZones.UTC, AccessRights = AccessRights.FullAccess)]
public class TradeTime : Robot
{
private TimeSpan _startTime, _endTime;
[Parameter("Start Time", DefaultValue = "07:00:00", Group = "Time Filter")]
public string StartTime { get; set; }
[Parameter("End Time", DefaultValue = "16:00:00", Group = "Time Filter")]
public string EndTime { get; set; }
private DateTime CurrentTime
{
get { return Server.TimeInUtc.Add(-Application.UserTimeOffset); }
}
private bool IsTimeCorrect
{
get { return (_startTime > _endTime && (CurrentTime.TimeOfDay >= _startTime || CurrentTime.TimeOfDay <= _endTime)) || (_startTime < _endTime && (CurrentTime.TimeOfDay >= _startTime && CurrentTime.TimeOfDay <= _endTime)); }
}
protected override void OnStart()
{
if (!TimeSpan.TryParse(StartTime, CultureInfo.InvariantCulture, out _startTime))
{
Print("Invalid start time input");
Stop();
}
if (!TimeSpan.TryParse(EndTime, CultureInfo.InvariantCulture, out _endTime))
{
Print("Invalid end time input");
Stop();
}
}
protected override void OnBar()
{
// Return if current time is not in start/end time range
if (!IsTimeCorrect) return;
}
}
}
Please take a look on Server.Time, Server.TimeInUtc, Application.UserTimeOffset, .NET TimeSpan, and DateTime.
If you know the C# basics and cTrader automate API references then you can easily do it.
@amusleh
amusleh
09 Apr 2021, 21:48
Hi,
The Bars LoadMoreHistory method loads more historical data and allows you to do it via code, it doesn't notify you when user loads more data.
Whenever the indicator initialize method is called it means either more data is loaded or platform re-connected after disconnection, that's the time you can check your saved data file on the disk and load the data from it to your outputs instead of re-calculating.
@amusleh