Topics
Forum Topics not found
Replies
amusleh
24 Mar 2021, 09:19
RE: RE: RE:
kebbo said:
amusleh said:
kebbo said:
Hi,
thank you very much for your detailed answer!
I will test this once, however, I do not have so much experience with web requests, possibly there are difficulties with the implementation.
Is it possible to access the time information that is displayed at the bottom right of the platform at "current time:"?
Thank you!
I updated the code, please try again.
Thanks again for your effort!
I would like to get along without WebRequests.
Do you have any other ideas, or are you convinced that there is no other way?Is it possible to access the time displayed at the bottom right of cTrader? This time is retrieved directly from the server, isn't it?
When backtesting, I need the current time and not the times of the respective candle, and also not the system time of the executing PC, but the current server time...
It would be great if you could help me.
Many greetings and many thanks
Not sure but I don't think its possible to get the current server time during back test, getting time from web request is one option, if you Google you might find other options.
@amusleh
amusleh
24 Mar 2021, 09:17
Try this:
using cAlgo.API;
using cAlgo.API.Internals;
using System.Collections.Generic;
using System.Linq;
namespace cAlgo
{
[Indicator(IsOverlay = true, TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
public class Callindicator : Indicator
{
private Symbol[] _symbols;
private Bars[] _bars;
[Parameter("Symbols", DefaultValue = "EURUSD,GBPUSD,USDJPY,USDCHF,AUDCAD,AUDCHF,AUDJPY,AUDNZD,AUDUSD,CADCHF,CADJPY")]
public string SymbolNames { get; set; }
[Parameter("Bigger Timeframe", DefaultValue = "Daily")]
public TimeFrame TimeframeBigger { get; set; }
public int IndexMinDaily = 0;
public int MinIndexB = 0;
public double MinLineB = 0;
public int IndexMaxDaily = 0;
public int MaxIndexB = 0;
public double MaxLineB = 0;
public bool is_minB = false;
public bool is_maxB = false;
public List<Extremum> extremums = new List<Extremum>();
public int lastHighindexB;
public int LastLowindexB;
public bool isBuy_allowedB = true;
public bool isSell_allowedB = true;
public bool signal_BuyB = false;
public bool signal_SellB = false;
public double high_insideB;
public double low_insideB;
public int lastbuy_exIndexB;
public int lastsell_exIndexB;
private MarketSeries Biggermarketseries;
private int lastIndex = 0;
protected override void Initialize()
{
_symbols = Symbols.GetSymbols(SymbolNames.Replace(" ", string.Empty).Split(',').ToArray());
_bars = _symbols.Select(iSymbol => MarketData.GetBars(TimeframeBigger, iSymbol.Name)).ToArray();
foreach (var bars in _bars)
{
while (bars.Count < 1000)
{
var loadedCount = bars.LoadMoreHistory();
Print("Loaded {0} bars of {1}", loadedCount, bars.SymbolName);
if (loadedCount == 0)
break;
}
bars.Tick += Bars_Tick;
bars.BarOpened += Bars_BarOpened;
}
Biggermarketseries = MarketData.GetSeries(TimeframeBigger);
int index = Bars.Count - 2;
int idx1 = Biggermarketseries.OpenTime.GetIndexByTime(MarketSeries.OpenTime[index]);
int indaxstart = idx1 - 10;
MinIndexB = indaxstart;
MinLineB = double.MaxValue;
MaxIndexB = indaxstart;
MaxLineB = double.MinValue;
}
private void Bars_BarOpened(BarOpenedEventArgs obj)
{
// each symbol will call this method on new bar open
}
private void Bars_Tick(BarsTickEventArgs obj)
{
// each symbol will call this method on tick change
}
public override void Calculate(int index)
{
foreach (var symbol in _symbols)
{
// run indicator for each symbol
}
int idx1 = Biggermarketseries.OpenTime.GetIndexByTime(MarketSeries.OpenTime[index]);
// index daily
int idx2 = MarketSeries.OpenTime.GetIndexByTime(Biggermarketseries.OpenTime[idx1]);
Bars barsD1 = MarketData.GetBars(TimeFrame.Daily);
Bars barsH1 = MarketData.GetBars(TimeFrame.Hour);
if (is_maxB && Biggermarketseries.High[idx1 - 1] > MaxLineB)
{
MaxLineB = Biggermarketseries.High[idx1 - 1];
MaxIndexB = findindexmax(idx2, MaxLineB);
}
Chart.DrawStaticText("text", index + SymbolName, VerticalAlignment.Bottom, HorizontalAlignment.Left, Color.Red);
returnfun(MaxIndexB);
}
public string returnfun(int index)
{
return index + SymbolName;
}
public int findindexmax(int index, double high)
{
for (int i = index - 24; i <= index + 24; i++)
{
if (high == Bars.HighPrices[i])
return i;
}
return index;
}
}
}
You can put any code you want to inside "Bars_BarOpened" and "Bars_Tick" methods, you can use the Calculate method to calculate the indicator for historical data, its called only for current chart symbol ticks not your other symbols, so instead use "Bars_Tick" method.
Now you have all you need, the symbols and their bars, and you can pass the symbols via a parameter instead of hard coding the symbol names inside your indicator.
@amusleh
amusleh
23 Mar 2021, 15:02
Hi,
Try StringBuilder:
using cAlgo.API;
using System.Text;
namespace cAlgo
{
[Indicator(IsOverlay = true, TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
public class Blank : Indicator
{
protected override void Initialize()
{
var stringBuilder = new StringBuilder();
stringBuilder.AppendLine("First Text");
stringBuilder.AppendLine("Second Text");
var text = stringBuilder.ToString();
Chart.DrawText("text", text, Chart.LastVisibleBarIndex, Bars.HighPrices[Chart.LastVisibleBarIndex], Color.Red);
}
public override void Calculate(int index)
{
}
}
}
With string builder you can easily add as many line as you want to, and then you just have to call the DrawText once.
You can't use font size, that's for chart controls not chart objects.
@amusleh
amusleh
22 Mar 2021, 21:16
I recommend you to first learn and have some basic understanding of C# code and then try to code indicators/cBots.
The cBot link you posted is a simple cBot that uses RSI indicator for taking trading signals, you don't have to create an indicator from a cBot, usually its the opposite way.
If you don't have enough time to learn C# then you can ask one of our consultants to do it for you or post a job on jobs page.
Here is RSI indicator that sends email notification and play sound based on the cBot 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 RSIAlertSample : Indicator
{
private RelativeStrengthIndex _rsi;
private int _lastNotifiedBarIndex;
[Parameter("Source")]
public DataSeries Source { get; set; }
[Parameter("Periods", DefaultValue = 10)]
public int Period { get; set; }
[Parameter("Sound File Path", DefaultValue = "C:\\Windows\\Media\\notify.wav")]
public string SoundFilePath { get; set; }
[Parameter("Sender Email")]
public string SenderEmail { get; set; }
[Parameter("Receiver Email")]
public string ReceiverEmail { get; set; }
protected override void Initialize()
{
_rsi = Indicators.RelativeStrengthIndex(Source, Period);
}
public override void Calculate(int index)
{
if (!IsLastBar || _lastNotifiedBarIndex == index) return;
_lastNotifiedBarIndex = index;
if (_rsi.Result.Last(1) > 50 && _rsi.Result.Last(1) < 70 && _rsi.Result.IsRising())
{
Notify("RSI Buy Signal");
}
else if (_rsi.Result.Last(1) < 50 && _rsi.Result.Last(1) > 30 && _rsi.Result.IsFalling())
{
Notify("RSI Sell Signal");
}
}
private void Notify(string message)
{
if (!string.IsNullOrWhiteSpace(SoundFilePath))
{
Notifications.PlaySound(SoundFilePath);
}
if (!string.IsNullOrWhiteSpace(SenderEmail) && !string.IsNullOrWhiteSpace(ReceiverEmail))
{
Notifications.SendEmail(SenderEmail, ReceiverEmail, "Notification", message);
}
}
}
}
@amusleh
amusleh
22 Mar 2021, 20:12
RE:
kebbo said:
Hi,
thank you very much for your detailed answer!
I will test this once, however, I do not have so much experience with web requests, possibly there are difficulties with the implementation.
Is it possible to access the time information that is displayed at the bottom right of the platform at "current time:"?
Thank you!
I updated the code, please try again.
@amusleh
amusleh
22 Mar 2021, 17:20
( Updated at: 22 Mar 2021, 20:11 )
You can use this class to get the current time:
public static DateTimeOffset GetTime()
{
var currentTime = DateTimeOffset.Now;
string[] hosts =
{
"http://www.google.com",
"http://www.microsoft.com",
"http://timezonedb.com/",
"http://www.twitter.com",
"http://spotware.com",
};
Parallel.ForEach(hosts, (host, loopState) =>
{
try
{
if (loopState.ShouldExitCurrentIteration)
{
return;
}
var response = WebRequest.Create(host).GetResponse();
if (loopState.ShouldExitCurrentIteration)
{
return;
}
currentTime = DateTime.ParseExact(
response.Headers["date"],
"ddd, dd MMM yyyy HH:mm:ss 'GMT'",
CultureInfo.InvariantCulture.DateTimeFormat
, DateTimeStyles.AssumeUniversal).ToLocalTime();
if (loopState.ShouldExitCurrentIteration)
{
return;
}
loopState.Stop();
}
catch (Exception ex) when (ex is WebException || ex is FormatException)
{
}
});
return currentTime;
}
If the system isn't connected to internet or there was any other issue in connection with listed hosts the method will return DateTimeOffset.Now which is the current time of user system, modify it based on your needs.
@amusleh
amusleh
22 Mar 2021, 17:12
Server.Time works very well on back test, if you use the server time on back test it will give you the time based on back test time not current time.
If you want to get the current time during back test you can use the DateTimeOffset.Now and then change its offset to server time offset, its still dependent to user system time.
If you need the current time but you don't want to use the user system time then you can use a web request, the current time will be on request header.
@amusleh
amusleh
22 Mar 2021, 14:26
( Updated at: 22 Mar 2021, 15:23 )
I was able to build your posted indicator code on my system without any issue on Spotware cTrader beta.
Please create a new indicator, copy the code of your old indicator, and try to re-build.
I recommend you to use Visual Studio, it will mark the error for you.
@amusleh
amusleh
21 Mar 2021, 18:14
RE: RE:
lec0456 said:
Thanks, but what i am really looking for it that the tooltip appears when the mouse rolls over the Output line. So, if Main is the moving average, when you rollover main it displays the text at the point you rolled over the line.
The sample I posted does the same thing, please test.
@amusleh
amusleh
21 Mar 2021, 13:16
Hi,
This sample indicator might help you:
using cAlgo.API;
using cAlgo.API.Indicators;
using System;
namespace cAlgo
{
/// <summary>
/// This sample shows how to create a tooltips for an indicator data series or output
/// </summary>
[Indicator(IsOverlay = false, TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
public class OutputSnapshotSample : Indicator
{
private MarketSnapshotControl _marketSnapshotControl;
private MovingAverage _ma;
[Parameter("Tolerance (Pips)", DefaultValue = 8)]
public double ToleranceInPips { get; set; }
[Output("Main", LineColor = "Yellow", PlotType = PlotType.Line, Thickness = 1)]
public IndicatorDataSeries Main { get; set; }
protected override void Initialize()
{
ToleranceInPips *= Symbol.PipSize;
_ma = Indicators.MovingAverage(Bars.ClosePrices, 9, MovingAverageType.Exponential);
_marketSnapshotControl = new MarketSnapshotControl
{
BackgroundColor = Color.Gold,
BorderColor = Color.Gray,
VerticalAlignment = VerticalAlignment.Top,
HorizontalAlignment = HorizontalAlignment.Left,
Opacity = 0.6,
Margin = 2,
IsVisible = false,
Width = 220,
Height = 50
};
IndicatorArea.AddControl(_marketSnapshotControl);
IndicatorArea.MouseMove += IndicatorArea_MouseMove;
IndicatorArea.MouseLeave += IndicatorArea_MouseLeave;
}
private void IndicatorArea_MouseMove(ChartMouseEventArgs obj)
{
var index = (int)obj.BarIndex;
var yValue = Math.Round(obj.YValue, Symbol.Digits);
var mainValue = Math.Round(Main[index], Symbol.Digits);
if (double.IsNaN(mainValue) || Math.Abs(mainValue - yValue) > ToleranceInPips)
{
_marketSnapshotControl.IsVisible = false;
return;
}
var extraDelta = 10;
var width = _marketSnapshotControl.Width;
var height = _marketSnapshotControl.Height;
var left = Chart.Width - obj.MouseX > width + extraDelta ? obj.MouseX + extraDelta : obj.MouseX - width - extraDelta;
var right = Chart.Height - obj.MouseY > height + extraDelta ? obj.MouseY + extraDelta : obj.MouseY - height - extraDelta;
_marketSnapshotControl.Margin = new Thickness(left, right, 0, 0);
_marketSnapshotControl.Time = Bars.OpenTimes[index].ToString("g");
_marketSnapshotControl.Value = mainValue.ToString();
_marketSnapshotControl.IsVisible = true;
}
private void IndicatorArea_MouseLeave(ChartMouseEventArgs obj)
{
_marketSnapshotControl.IsVisible = false;
}
public override void Calculate(int index)
{
Main[index] = _ma.Result[index];
}
}
public class MarketSnapshotControl : CustomControl
{
private readonly Border _border;
private TextBlock _valueTextBlock;
private TextBlock _timeTextBlock;
public MarketSnapshotControl()
{
_border = new Border
{
BackgroundColor = "#3F3F3F",
BorderColor = "#969696",
BorderThickness = 1,
CornerRadius = 5
};
var style = new Style();
style.Set(ControlProperty.Margin, new Thickness(3, 3, 0, 0));
style.Set(ControlProperty.FontWeight, FontWeight.Bold);
style.Set(ControlProperty.ForegroundColor, Color.Black);
style.Set(ControlProperty.HorizontalContentAlignment, HorizontalAlignment.Left);
style.Set(ControlProperty.VerticalContentAlignment, VerticalAlignment.Center);
_valueTextBlock = new TextBlock
{
Style = style
};
_timeTextBlock = new TextBlock
{
Style = style
};
var grid = new Grid(2, 2)
{
ShowGridLines = true
};
grid.AddChild(new TextBlock
{
Text = "Value",
Style = style
}, 0, 0);
grid.AddChild(new TextBlock
{
Text = "Time",
Style = style
}, 1, 0);
grid.AddChild(_valueTextBlock, 0, 1);
grid.AddChild(_timeTextBlock, 1, 1);
_border.Child = grid;
AddChild(_border);
}
public Color BackgroundColor
{
get { return _border.BackgroundColor; }
set { _border.BackgroundColor = value; }
}
public Color BorderColor
{
get { return _border.BorderColor; }
set { _border.BorderColor = value; }
}
public string Value
{
get { return _valueTextBlock.Text; }
set { _valueTextBlock.Text = value; }
}
public string Time
{
get { return _timeTextBlock.Text; }
set { _timeTextBlock.Text = value; }
}
}
}
The only issue with sample is tolerance parameter, you have to find a way to calculate a good tolerance that works well for all symbols and outputs, you can do it by using an output x previous values average difference or change, or you can use percentage change in output.
If the tooltips is not showing for some very volatile symbols like BTCUSD then try to increase the tolerance.
There might be other better ways to achieve this but right now this is the only option in my mind.
@amusleh
amusleh
20 Mar 2021, 19:26
RE: RE:
westend.trading said:
PanagiotisCharalampous said:
Hi westend.trading,
Our economic calendar is provided by a third party source and we do not have the right to redistribute the information. You can contact these providers yourself and ask about direct access to the calendar.
Best Regards,
Panagiotis
Hi Panagiotis,
it sounds paradox since this information is somehow distributed by the cTrader app anyway. But if that is the way it is...
It is giving MT5 a head start, though.Best regards,
Ben;
You can get the news data from 3rd party services like TradingEconomics API.
@amusleh
amusleh
19 Mar 2021, 16:07
RE: RE: RE:
duketv said:
amusleh said:
Hi,
The code above checks last MA value which is not closed yet and can change, so it can go above or below last closed bar price.
You should use Last(1) not LastValue:
if (Bars.Last(1).Open < Sma.Result.Last(1) && Bars.Last(1).Close > Sma.Result.Last(1)) { }
Last(1) gives you the latest closed value, and LastValue gives you the last value of series which is not closed yet and can change which will give you inconsistent results both in backtest and live.
You can use Last(2) to get the last second closed value of a series.
Thank you, That is indeed some valuable information for further coding.. A small but not unimportant detail!
Still curious how the hascrossedabove method works though? My interpretation of 'hascrossedabove' is that after crossing, the method will return true for an x amount of bars. X being the 'int Period' from the method. However, I do see an irregular amount 'true' when I code for this.
You can read the documentation of HasCroossedAbove method here:
@amusleh
amusleh
19 Mar 2021, 12:10
Hi,
There is no way to disable the log right now, but you can use the .NET sound player instead of Notifications.PlaySound method and it will not product any log.
private static void PlaySound(string path)
{
if (string.IsNullOrWhiteSpace(path)) throw new ArgumentException($"'{nameof(path)}' cannot be null or whitespace", nameof(path));
SoundPlayer soundPlayer = null;
try
{
soundPlayer = new SoundPlayer(path);
soundPlayer.PlaySync();
}
finally
{
if (soundPlayer != null) soundPlayer.Dispose();
}
}
You have to add "using System.Media" for the above code to work.
@amusleh
amusleh
19 Mar 2021, 11:36
Hi,
This sample bot might help you:
using cAlgo.API;
using cAlgo.API.Internals;
using System;
using System.Linq;
namespace cAlgo.Robots
{
[Robot(TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
public class BarBreakoutTradingSample : Robot
{
private double _volumeInUnits;
[Parameter("Breakount Amount (Pips)", DefaultValue = 10, MinValue = 0)]
public double BreakountAmountInPips { get; set; }
[Parameter("Volume (Lots)", DefaultValue = 0.01)]
public double VolumeInLots { get; set; }
[Parameter("Label", DefaultValue = "BarBreakoutTradingSample")]
public string Label { get; set; }
public Position[] BotPositions
{
get
{
return Positions.Where(iPosition => Label.Equals(iPosition.Label, StringComparison.OrdinalIgnoreCase)
&& iPosition.SymbolName.Equals(SymbolName, StringComparison.OrdinalIgnoreCase))
.ToArray();
}
}
protected override void OnStart()
{
if (string.IsNullOrWhiteSpace(Label))
{
Print("Please provide a label");
Stop();
}
BreakountAmountInPips *= Symbol.PipSize;
_volumeInUnits = Symbol.QuantityToVolumeInUnits(VolumeInLots);
}
protected override void OnTick()
{
if (BotPositions.Length > 0) return;
if (Symbol.Ask >= Bars.Last(1).High + BreakountAmountInPips)
{
ExecuteMarketOrder(TradeType.Buy, SymbolName, _volumeInUnits, Label);
}
else if (Symbol.Bid <= Bars.Last(1).Low - BreakountAmountInPips)
{
ExecuteMarketOrder(TradeType.Sell, SymbolName, _volumeInUnits, Label);
}
}
protected override void OnBar()
{
foreach (var position in BotPositions)
{
if ((position.TradeType == TradeType.Buy && Bars.Last(1).Close < Bars.Last(1).Open)
|| (position.TradeType == TradeType.Sell && Bars.Last(1).Close > Bars.Last(1).Open))
{
ClosePosition(position);
}
}
}
}
}
Please read the API references if its hard to understand the sample bot code.
@amusleh
amusleh
19 Mar 2021, 11:03
Hi,
You can use order label parameter to set unique ID for orders, add a string type label parameter to your bot and then use that parameter value as your bot executed orders label, the other bot can use the same label to filter the orders and find the previous bot opened orders.
@amusleh
amusleh
24 Mar 2021, 09:23
There are different ways to show a popup message box, the simplest option is to use WinForms dialogs:
The MessageBox is inside System.Windows.Forms, so you have to reference that assembly for the above code to work.
If you need something more advanced you can use the open source ctrader-alert_popup library.
@amusleh