Topics
Replies
firemyst
06 Sep 2021, 16:01
RE:
hao.han said:
Hi, I was someone could help me with some suggestions on how to solve this problem:
High level issue: I have a portfolio of trading cBots running (so 2 or more). How can I halt all trading if account equity falls below X, akin to an "account/portfolio stop loss", until instructed otherwise.
Elaboration: I do not necessarily care exactly how the effect of the stop loss achieved. For example, there may be a variable in a cBot that acts like a switch to say if trades can/cannot be executed. Or something that automatically switches off all cBots (after first closing all positions). But most importantly, simply "closing all positions" is not sufficient as I want to prevent all cBots from opening further trades until instructed otherwise (which can be either manual or by code - such as "wait Y hours, then allow trades again").
I read briefly in another forum about potentially using "named pipes", but my programming skills are not amazing, and this seems like quite a difficult way to achieve the desired effect.
Any thoughts/suggestions would be greatly appreciated (an example would be amazing also).
Thank you
IN each bot, in the OnTick method, just check the equity of your account:
//Get your position if any
Position p = Positions.Find(someLabel, Symbol.Name);
//Checks the equity of the account
if (Account.Equity <= someValue)
{
//If we have a position open, close it
if (p != null)
p.Close();
Stop(); //Stop this bot instance
}
else
{
//keep going and do whatever
}
@firemyst
firemyst
30 Aug 2021, 17:54
RE:
amosmsiwa said:
In trying to keep the programming code as clean as possible, can the CRL indentify these as identical statements or not?
if ((_macdH.Histogram.LastValue > _macdH.Signal.LastValue) && (_macdH.Histogram.LastValue - _macdH.Signal.LastValue > 0))
{
if ((_stochO.PercentK.LastValue > _stochO.PercentD.LastValue) || (_stochO.PercentK.LastValue > 50))
{
if ((_rsi.Result.LastValue > 51) && (_pSar.Result.LastValue < MarketSeries.Close.LastValue))
{
Print("BUY...." + this.Symbol);
}
}
if ((_macdH.Histogram.LastValue > _macdH.Signal.LastValue) && (_macdH.Histogram.LastValue - _macdH.Signal.LastValue > 0)) &&((_stochO.PercentK.LastValue > _stochO.PercentD.LastValue) || (_stochO.PercentK.LastValue > 50))(_rsi.Result.LastValue > 51) && (_pSar.Result.LastValue < MarketSeries.Close.LastValue))
{
Print("BUY...." + this.Symbol);
}
This should work for you:
if (
((_macdH.Histogram.LastValue > _macdH.Signal.LastValue) && (_macdH.Histogram.LastValue - _macdH.Signal.LastValue > 0))
&&
((_stochO.PercentK.LastValue > _stochO.PercentD.LastValue) || (_stochO.PercentK.LastValue > 50))
&&
((_rsi.Result.LastValue > 51) && (_pSar.Result.LastValue < MarketSeries.Close.LastValue))
)
{
Print("BUY...." + this.Symbol);
}
However, your original code may be better in the long run because it's already formatted for extra flexibility. For instance, if you're trying to understand why certain trades aren't happening, you would probably want to do something like this:
if ((_macdH.Histogram.LastValue > _macdH.Signal.LastValue) && (_macdH.Histogram.LastValue - _macdH.Signal.LastValue > 0))
{
if ((_stochO.PercentK.LastValue > _stochO.PercentD.LastValue) || (_stochO.PercentK.LastValue > 50))
{
if ((_rsi.Result.LastValue > 51) && (_pSar.Result.LastValue < MarketSeries.Close.LastValue))
{
Print("BUY...." + this.Symbol);
}
else if (_rsi.Result.LastValue <= 51)
{
Print("RSI last value {0} is not > 51", _rsi.Result.LastValue);
}
else if (_pSar.Result.LastValue >= MarketSeries.Close.LastValue)
{
Print("PSAR last value {0} >= MarketServers Close LastValue {1}", _pSar.Result.LastValue, MarketSeries.Close.LastValue);
}
}
else if (_stochO.PercentK.LastValue <= 50)
{
Print("Stoch %K last value {0} is <= 50", _stochO.PercentK.LastValue);
}
//
// ... etc etc etc ...
//
}
else if ( ... )
{
//
// ... etc etc etc ...
//
}
Then you can review the logs and fully grasp what is or isn't happening and why.
@firemyst
firemyst
30 Aug 2021, 17:29
RE:
ctid2032775 said:
Dear all,
maybe I am doing something wrong and someone of you can point me into the right direction...
My cBot runs an integrated optimization process OnStart and on specific circumstances (e. g. MDD increasing) that takes a lot of CPU and memory - i. e. quite "resource hungry". After this process is successfully finished the cBot is switched into "Trading" mode and starts trading OnBar.
At the beginning of the optimization process I want to print a static text (e. g. "Optimizing - EURUSD") and before start trading I want to print another static text (e. g. "Trading - EURUSD - Par1 = xxx - Par2 = yyy"; Par1 and Par2 are the results of the optimization) to the chart.
The small "beauty mistake" now is that the optimizing text is not output to the chart - is there a way to "force" the output even while the cBot is quite busy?
Many thanks in advance and best regards,
Christian
I would write the information out to the log because not all text/drawings on the chart are supported during back-testing as far as I'm aware.
Eg, if (IsBacktesting) { ... print your text to the log... } else { drawstatictext on chart }
@firemyst
firemyst
29 Aug 2021, 12:25
RE:
Nickachino said:
Hi,
I m trying to use 2 EMAs from a custom multi timeframe indicators. I get an error when I call the indicator in my cBot.
This is the indicator code:
using System;
using cAlgo.API;
using cAlgo.API.Internals;
using cAlgo.API.Indicators;
namespace cAlgo.Indicators
{
[Indicator(IsOverlay = true, TimeZone = TimeZones.UTC)]
public class MyMTFEMA : Indicator
{
[Parameter(DefaultValue = 8)]
public int EMAPeriods1 { get; set; }
[Parameter(DefaultValue = 21)]
public int EMAPeriods2 { get; set; }
[Parameter("EMA Timeframe1", DefaultValue = "Hour")]
public TimeFrame EMATimeframe1 { get; set; }
[Parameter("EMA Timeframe2", DefaultValue = "Hour")]
public TimeFrame EMATimeframe2 { get; set; }
[Output("EMA1", Color = Colors.Blue)]
public IndicatorDataSeries EMA1 { get; set; }
[Output("EMA2", Color = Colors.Red)]
public IndicatorDataSeries EMA2 { get; set; }
private MarketSeries series1;
private MarketSeries series2;
private ExponentialMovingAverage Ema1;
private ExponentialMovingAverage Ema2;
protected override void Initialize()
{
series1 = MarketData.GetSeries(EMATimeframe1);
series2 = MarketData.GetSeries(EMATimeframe2);
Ema1 = Indicators.ExponentialMovingAverage(series1.Close, EMAPeriods1);
Ema2 = Indicators.ExponentialMovingAverage(series2.Close, EMAPeriods2);
}
public override void Calculate(int index)
{
var index1 = GetIndexByDate(series1, MarketSeries.OpenTime[index]);
if (index1 != -1)
{
EMA1[index] = Ema1.Result[index1];
}
var index2 = GetIndexByDate(series2, MarketSeries.OpenTime[index]);
if (index2 != -1)
{
EMA2[index] = Ema2.Result[index2];
}
}
private int GetIndexByDate(MarketSeries series, DateTime time)
{
for (int i = series.Close.Count - 1; i > 0; i--)
{
if (time == series.OpenTime[i])
return i;
}
return -1;
}
}
}The I call it like this:
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 SIMPLEandPROFITABLEForexScalping : Robot
{
[Parameter("Risk %", DefaultValue = 0.02)]
public double RiskPct { get; set; }
[Parameter("EMA1 period", DefaultValue = 8)]
public int EMA1Period { get; set; }
[Parameter("EMA2 period", DefaultValue = 13)]
public int EMA2Period { get; set; }
[Parameter("EMA3 period", DefaultValue = 21)]
public int EMA3Period { get; set; }
private MovingAverage EMA1;
private MovingAverage EMA2;
private MovingAverage EMA3;
private MyMTFEMA MTFEMA;
protected override void OnStart()
{
// Put your initialization logic here
EMA1 = Indicators.MovingAverage(Bars.ClosePrices, EMA1Period, MovingAverageType.Exponential);
EMA2 = Indicators.MovingAverage(Bars.ClosePrices, EMA2Period, MovingAverageType.Exponential);
EMA3 = Indicators.MovingAverage(Bars.ClosePrices, EMA3Period, MovingAverageType.Exponential);
MTFEMA = Indicators.GetIndicator<MyMTFEMA>(8, 21, "Hour", "Hour");
}However I get an error when trying to run the cBot with this message:
31/12/2019 02:00:00.000 | Backtesting started
31/12/2019 02:00:00.000 | Crashed in OnStart with AlgoActivationException: Can not set "Hour" as a value for "EMATimeframe1" parameter
31/12/2019 02:00:00.000 | Backtesting was stopped
I have tried various ways to change the way I call the parameters using the 8, 21 and two "Hour" options but still get an error.
Any assistance would be appreciated.
Of course it's crashing there. You're passing in "Hour" as a string. The parameter is specifically for a TimeFrame object.
So you have to pass the timeframe similar to:
MTFEMA = Indicators.GetIndicator<MyMTFEMA>(8, 21, TimeFrame.Hour, TimeFrame.Hour);
@firemyst
firemyst
29 Aug 2021, 12:21
RE:
herculesone said:
Hello there!
I would like some help to make an indicator, which is fairly simple but does not show as I want it.
I would like to show the closing prices of different timeframes on the same chart. However, I am unable to make the chart match the output I want to show.
Here is the code:
using System;
using cAlgo.API;
using cAlgo.API.Internals;
using cAlgo.API.Indicators;
using cAlgo.Indicators;
namespace cAlgo
{
[Indicator(IsOverlay = true, TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
public class Closes_4hr_D_W_M_Q_Y : Indicator
{
[Output("4 Hour", LineColor = "Green", PlotType = PlotType.Points, Thickness = 2)]
public IndicatorDataSeries Hour4 { get; set; }
[Output("Daily", LineColor = "Black", PlotType = PlotType.Line, LineStyle = LineStyle.Solid, Thickness = 2)]
public IndicatorDataSeries Daily { get; set; }
[Output("Weekly", LineColor = "Red", PlotType = PlotType.Line, LineStyle = LineStyle.Solid, Thickness = 2)]
public IndicatorDataSeries Weekly { get; set; }
[Output("Monthly", LineColor = "Navy", PlotType = PlotType.Line, LineStyle = LineStyle.Solid, Thickness = 2)]
public IndicatorDataSeries Monthly { get; set; }
public Bars _daily, _4h, _weekly, _month;protected override void Initialize()
{
_4h = MarketData.GetBars(TimeFrame.Hour4);
_daily = MarketData.GetBars(TimeFrame.Daily);
_weekly = MarketData.GetBars(TimeFrame.Weekly);
_month = MarketData.GetBars(TimeFrame.Monthly);
}
public override void Calculate(int index)
{
Hour4[index] = _4h.ClosePrices[index];
Daily[index] = _daily.ClosePrices[index];
Weekly[index] = _weekly.ClosePrices[index];
Monthly[index] = _month.ClosePrices[index];
}
}
}
I would expect that on a 1 hour chart, the Daily output would show as a straight line until the next day, when there would be another straight line etc. Instead, the indicators paint further back as if they are attached to another chart.
It is like the "index" applies to the chart I am calling and not the "index" of the applicable chart, which does make sense in a way but I want to work around it and cannot figure out how.
In essence when I call "index" of a 1 hour chart, the price on the daily chart of the same index should be the same until all the hours are complete.
Any help is appreciated, thank you!
The index of the current chart won't be the same as the index on the other timeframe charts.That's why you're having the issue. For all the timeframes, you're getting the current index on the chart you're viewing. Since there's significantly more bars on the H4 chart than there are in the D1 chart for the day, you're going to have multiple incorrect readings.
For instance, when viewing the H4 chart, you need to get the corresponding index on the D, W, and M charts.
//Example code to get the correct Daily index on the H4 chart in the Calculate method.
//This code assumes you'll always be looking at the H4 chart.
int altIndexD1 = _daily.OpenTimes.GetIndexByTime(Bars.OpenTimes[index]);
@firemyst
firemyst
24 May 2021, 16:58
RE:
PanagiotisCharalampous said:
Hi firemyst,
Check Chart.Drag and Chart.ObjectsUpdated events.
Best Regards,
Panagiotis
Thanks for that.
Another question. I have the following sample code -- see my question in the commented code:
using System;
using System.Collections.Generic;
using cAlgo.API;
using cAlgo.API.Indicators;
namespace cAlgo.Indicators
{
[Indicator(IsOverlay = true, AccessRights = AccessRights.None)]
public class Test : Indicator
{
private ChartHorizontalLine _chl;
private double _value;
protected override void Initialize()
{
_value = MarketData.GetBars(Chart.TimeFrame, Symbol.Name).ClosePrices.LastValue;
_chl = Chart.DrawHorizontalLine("test line", _value, Color.Goldenrod, 2, LineStyle.Solid);
_chl.IsInteractive = true;
Chart.ObjectsUpdated += LineUpdated;
}
public override void Calculate(int index)
{
}
//When I drag the horizontal line created on the chart, why does this method get called numerous times?
//Every time I drag the line, if I set a breakpoint on the opening curly brace, this method gets hit for each
//object on the chart.
//Is there a way to to reduce this so it only gets called for horizontal line objects?
private void LineUpdated(ChartObjectsUpdatedEventArgs args)
{
ChartHorizontalLine obj = (ChartHorizontalLine)args.Chart.FindObject("test line");
if (obj != null && obj.Y != _value)
{
_value = obj.Y;
Chart.DrawStaticText("value", _value.ToString(), VerticalAlignment.Top, HorizontalAlignment.Right, Color.Goldenrod);
}
}
}
}
@firemyst
firemyst
29 Apr 2021, 06:24
cTrader is unfortunately very limited in its alerting abilities, and I think the only alerts possible are those based on "price". Although I'm sure someone from Spotware can correct me if I'm wrong.
If you need this, I see a few options:
1) sign up with another trading platform like ThinkTrader, which has awesome alerting functionality built in, where you can customize any kind of alert from one indicator crossing a price/indicator, price notifications, or a lot of other options.
2) program a 3 ema indicator yourself to alert you of when prices ema values are crossing.
3) use or find someone else's prebuilt indicator that has such alerting functionality provided.
@firemyst
firemyst
29 Apr 2021, 06:15
RE: RE:
bienve.pf said:
PanagiotisCharalampous said:
Hi bienve.pf,
The reason it doesn't move is because the retrieved bars are consist of completed bars. So you get the completed bar of the specific date. The price will change as soon as the date changes. There is a similar discussion about this here.
Best Regards,
Panagiotis
I understand,
But if I test multi-timeframe indicator in backtesting I need receive data like in realtime to parse all tics at the moment. Now, with all the finalized bars and finalized values the ClosePrices no moves and It is not a real stage.
Two questions:
1) have you chosen "tick data" from the backtesting menu option?
2) A lot of chart operations are not supported (as far as I understand) in backtesting mode. Try surrounding your indicator with
if (!IsBacktesting)
{
// ... indicator calls here
}
and see what happens.
@firemyst
firemyst
23 Apr 2021, 03:43
Glad that helped!
Something else to try is using IsLastBar such as follows:
if (!notified && IsLastBar())
{
notified = true;
PlaySound();
}
so it only plays on the last bar. If you're watching the charts live, this will be the most current bar. Thus you don't have to worry about the sound being played on any previous bars.
@firemyst
firemyst
22 Apr 2021, 10:16
( Updated at: 24 May 2022, 03:29 )
RE:
amusleh said:
Hi,
You can call Bars.OpenTimes.GetindexByTime two times with two indices, for example you call it first with index 5 and then 6, and it returns 10 for the first call and 20 for the second call, then you know from 10 to 20 belongs to first index.
Thank you!
That makes perfect sense!!
I appreciate your help!!
@firemyst
firemyst
22 Apr 2021, 09:42
( Updated at: 22 Apr 2021, 09:44 )
RE:
amusleh said:
Hi,
Indices are not fixed, they can change, instead use bar open times.
If you want to get index of a bar on a different time frame you can use GetIndexByTime method of Bars.OpenTimes, check this sample indicator code:
using cAlgo.API; using cAlgo.API.Indicators; using System; namespace cAlgo { [Cloud("Top", "Bottom", Opacity = 0.2)] [Indicator(IsOverlay = true, TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)] public class BollingerBandsMTFCloudSample : Indicator { private BollingerBands _bollingerBands; private Bars _baseBars; [Parameter("Base TimeFrame", DefaultValue = "Daily")] public TimeFrame BaseTimeFrame { get; set; } [Parameter("Source", DefaultValue = DataSeriesType.Close)] public DataSeriesType DataSeriesType { get; set; } [Parameter("Periods", DefaultValue = 14, MinValue = 0)] public int Periods { get; set; } [Parameter("Standard Deviation", DefaultValue = 2, MinValue = 0)] public double StandardDeviation { get; set; } [Parameter("MA Type", DefaultValue = MovingAverageType.Simple)] public MovingAverageType MaType { get; set; } [Output("Main", LineColor = "Yellow", PlotType = PlotType.Line, Thickness = 1)] public IndicatorDataSeries Main { get; set; } [Output("Top", LineColor = "Red", PlotType = PlotType.Line, Thickness = 1)] public IndicatorDataSeries Top { get; set; } [Output("Bottom", LineColor = "Red", PlotType = PlotType.Line, Thickness = 1)] public IndicatorDataSeries Bottom { get; set; } protected override void Initialize() { _baseBars = MarketData.GetBars(BaseTimeFrame); var baseSeries = GetBaseSeries(); _bollingerBands = Indicators.BollingerBands(baseSeries, Periods, StandardDeviation, MaType); } public override void Calculate(int index) { var baseIndex = _baseBars.OpenTimes.GetIndexByTime(Bars.OpenTimes[index]); Main[index] = _bollingerBands.Main[baseIndex]; Top[index] = _bollingerBands.Top[baseIndex]; Bottom[index] = _bollingerBands.Bottom[baseIndex]; } private DataSeries GetBaseSeries() { switch (DataSeriesType) { case DataSeriesType.Open: return _baseBars.OpenPrices; case DataSeriesType.High: return _baseBars.HighPrices; case DataSeriesType.Low: return _baseBars.LowPrices; case DataSeriesType.Close: return _baseBars.ClosePrices; default: throw new ArgumentOutOfRangeException("DataSeriesType"); } } } public enum DataSeriesType { Open, High, Low, Close } }
Thank you, but this doesn't help and doesn't work for what I need.
What your code is doing is getting the indexes of the bars in the faster time frame and mapping that to a single index to the bars in the slower time frame.
With your method, it's going from "many" to "one".
I need the opposite. I have 1 index in a higher time frame and need to map it to all the related indexes in the faster time frame.
I have "one" and need to map it to "many".
If you try doing the opposite:
Bars.OpenTimes.GetIndexByTime(_baseBars.OpenTimes[index]);
simply won't work because it will not return all the indexes related. That is, if _baseBars is M15, and the chart is M1, Bars.OpenTimes.GetindexByTime will only return 1 index, not the corresponding 15 indexes I need.
@firemyst
firemyst
22 Apr 2021, 09:21
RE:
sascha.dawe said:
Hi,
I am having trouble playing sound notifications in an indicator in the latest version of Ctrader 4.0.
Yes, I have sound enabled and notifications on Ctrader and Filesystem access is enabled. I have
also converted this code to a cBot and the sound works fine. What could be causing this issue?
See demonstration code below.
using System; using System.IO; using cAlgo.API; using cAlgo.API.Internals; using cAlgo.API.Indicators; using cAlgo.Indicators; namespace cAlgo { [Indicator(IsOverlay = true, TimeZone = TimeZones.UTC, AccessRights = AccessRights.FileSystem)] public class TestSound : Indicator { [Parameter("Enable Sound Alerts", Group = "Sound", DefaultValue = false)] public bool soundAlerts { get; set; } [Parameter("Sound Filename", Group = "Sound", DefaultValue = "foghorn.mp3")] public string filename { get; set; } private string path; private bool notified = false; protected override void Initialize() { try { var desktopFolder = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments); path = Path.Combine(desktopFolder, filename); Print(path); } catch (Exception error) { Print("Error: " + error); } PlaySound(); } public override void Calculate(int index) { if (!notified) { notified = true; PlaySound(); } } private void PlaySound() { if (soundAlerts) { try { Notifications.PlaySound(path); } catch (Exception error) { Print("Error: " + error); } } } } }
Have you tried stepping through your code in Visual Studio debug mode to see what happens?
Also, because ticks could be coming in rather quickly, the system might be trying to play, but then gets stopped immediately when the next tick comes in because the "notified" variable is never set to true. I've had that happen before when trying to play sounds too quickly in succession.
Finally, what's the Print/logging output?
@firemyst
firemyst
22 Apr 2021, 09:12
Rough pseudo logic:
DateTime startTime = new DateTime(2021,4,22,6,0,0);
int startTimeIndex = Bars.OpenTimes.GetIndexByTime(startTime);
DateTime endTime = new DateTime(2021,4,22,10,0,0);
int endTimeIndex = Bars.OpenTimes.GetIndexByTime(endTime);
double highestPrice = 0;
for (int x= startTimeIndex; x <= endTimeIndex; x++)
{
if (Bars.HighPrices[x] > highestPrice)
highestPrice = Bars.HighPrices[x];
}
@firemyst
firemyst
07 Sep 2021, 03:07 ( Updated at: 07 Sep 2021, 03:28 )
RE: RE: RE:
hao.han said:
Okay. So what? :-)
instead of having each bot instance close its own position, in all onTick methods, close ALL positions regardsless.
@firemyst