Topics
Forum Topics not found
Replies
amusleh
28 May 2021, 20:24
( Updated at: 28 May 2021, 20:25 )
RE: RE:
ctid2032775 said:
amusleh said:
Hi,
You should use a valid redirect URI, its clearly mentioned on WPF demo readme file.
The redirect URI on your application is for API playground, you can't use that, instead use something like: https://ctrader.com/
Hi,
many thanks for your hint - now the application starts as expected...
But, there is (at least) one issue - the chart area remains empty (even if it is possible to select different time frames)!
BR,
Christian
Hi,
Can you tell me on which broker trading account you tested the demo?
@amusleh
amusleh
28 May 2021, 20:24
Hi,
Not sure what you are after, is the line drawn on your chart by user while the cBot is running? if that's the case then you can iterate over Chart.Objects collection and find the line, then check the current price to see if it touched/crossed the line or not, this indicator is a sample:
using cAlgo.API;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
namespace cAlgo
{
[Indicator(IsOverlay = true, TimeZone = TimeZones.UTC, AccessRights = AccessRights.FullAccess)]
public class LineAlert : Indicator
{
private readonly List<ChartObjectAlert> _chartObjectAlerts = new List<ChartObjectAlert>();
[Parameter("Single Alert", DefaultValue = true, Group = "General")]
public bool SingleAlert { get; set; }
[Parameter("Trend/Ray", DefaultValue = true, Group = "Line Types")]
public bool TrendLine { get; set; }
[Parameter("Horizontal", DefaultValue = true, Group = "Line Types")]
public bool HorizontalLine { get; set; }
[Parameter("Vertical", DefaultValue = true, Group = "Line Types")]
public bool VerticalLine { get; set; }
[Parameter("Show Comment", DefaultValue = true, Group = "Comment")]
public bool ShowComment { get; set; }
[Parameter("Comment Suffix", Group = "Comment")]
public string CommentSuffix { get; set; }
[Parameter("Sound File", Group = "Alert")]
public string AlertSoundFile { get; set; }
protected override void Initialize()
{
}
public override void Calculate(int index)
{
foreach (var chartObject in Chart.Objects)
{
if (!string.IsNullOrEmpty(CommentSuffix) && !chartObject.Comment.EndsWith(CommentSuffix, StringComparison.InvariantCultureIgnoreCase))
{
continue;
}
var chartObjectAlert = new ChartObjectAlert
{
ChartObject = chartObject,
AlertBarIndex = index,
TouchType = TouchType.None
};
if (chartObject.ObjectType == ChartObjectType.TrendLine || chartObject.ObjectType == ChartObjectType.HorizontalLine)
{
var linePriceValue = double.NaN;
if (TrendLine && chartObject.ObjectType == ChartObjectType.TrendLine)
{
var chartTrendLine = chartObject as ChartTrendLine;
if (chartTrendLine != null)
linePriceValue = chartTrendLine.CalculateY(index);
}
else if (HorizontalLine && chartObject.ObjectType == ChartObjectType.HorizontalLine)
{
var chartHorizontalLine = chartObject as ChartHorizontalLine;
if (chartHorizontalLine != null)
linePriceValue = chartHorizontalLine.Y;
}
if (Bars.ClosePrices[index] >= linePriceValue && Bars.ClosePrices[index - 1] < linePriceValue)
{
chartObjectAlert.TouchType = TouchType.Up;
}
if (Bars.ClosePrices[index] <= linePriceValue && Bars.ClosePrices[index - 1] > linePriceValue)
{
chartObjectAlert.TouchType = TouchType.Down;
}
}
else if (VerticalLine && chartObject.ObjectType == ChartObjectType.VerticalLine)
{
var chartVerticalLine = chartObject as ChartVerticalLine;
if (chartVerticalLine != null && Bars.OpenTimes[index] >= chartVerticalLine.Time && Bars.OpenTimes[index - 1] < chartVerticalLine.Time)
{
chartObjectAlert.TouchType = TouchType.Right;
}
}
if (chartObjectAlert.TouchType != TouchType.None)
{
TriggerAlert(Bars.ClosePrices[index], chartObjectAlert);
}
}
}
private void TriggerAlert(double price, ChartObjectAlert chartObjectAlert)
{
var previousChartObjectAlert = _chartObjectAlerts.LastOrDefault(iChartObjectAlert => iChartObjectAlert.ChartObject == chartObjectAlert.ChartObject);
if ((SingleAlert && previousChartObjectAlert != null) || (previousChartObjectAlert != null && previousChartObjectAlert.AlertBarIndex == chartObjectAlert.AlertBarIndex))
{
return;
}
_chartObjectAlerts.Add(chartObjectAlert);
var touchType = string.Empty;
if (chartObjectAlert.TouchType == TouchType.Up)
{
touchType = "⬆";
}
else if (chartObjectAlert.TouchType == TouchType.Down)
{
touchType = "⬇";
}
else if (chartObjectAlert.TouchType == TouchType.Right)
{
touchType = "→";
}
Notifications.PlaySound(AlertSoundFile);
}
}
public class ChartObjectAlert
{
public ChartObject ChartObject { get; set; }
public int AlertBarIndex { get; set; }
public TouchType TouchType { get; set; }
}
public enum TouchType
{
None,
Up,
Down,
Right
}
}
The above indicator play's a sound file whenever price touches a line on your chart, the indicator uses line objects comment to find them, you have to use the same comment suffix on your line object comment.
That's a sample that you can use on your cBot for all line types including trend line.
@amusleh
amusleh
28 May 2021, 08:51
RE: RE:
chris07 said:
Hi amusleh,
will the new "Fibonacci drawing only indicator" have levels that can be extended all the way to the right? And can I change timeframes without loosing the drawings?
Thanks
Hi,
By default it doesn't extend the lines to infinity, but you can select a level and tick its extend to infinity checkbox and it will be extended to infinity.
Regarding changing time frames, if you change time frame all your drawing will be there on the sample location, it will not disappear.
@amusleh
amusleh
27 May 2021, 18:36
Hi,
You can't use reflection to get the user selected value for the output attribute properties.
It will give you the default value that you set on on your code, that's how reflection works, and unfortunately right now there is no way to get the user selected values for output attribute properties programmatically.
@amusleh
amusleh
27 May 2021, 09:52
( Updated at: 27 May 2021, 09:58 )
Hi,
Before sending a ProtoOANewOrderReq/ProtoOAClosePositionReq you must be subscribed to ProtoOAExecutionEvent, there is no individual response messages for trading requests, everything related to trading operations will go to the ProtoOAExecutionEvent.
When you receive a ProtoOAExecutionEvent you can check the deal field, this filed is of type ProtoOADeal which has the executionPrice of close price.
For more information regarding closed position you can use the ProtoOADeal closePositionDetail field.
Regarding calculation of P/L, once you got the position volume, entry and close price, you have to calculate each symbol tick value to calculate a position P/L.
You can check our new WPF trading UI Demo, the sample has all these features.
For a tutorial you can check our new documentation symbol data tutorial.
@amusleh
amusleh
26 May 2021, 14:46
Hi,
Please check the Checkbox and radio button example codes on API references.
@amusleh
amusleh
24 May 2021, 07:44
Hi,
Not all built-in indicators implement the IIndicator interface, or Indicator and Algo base classes, some do like Moving Averages.
The solution for you is to use Object as your List generic type, and then cast back from Object to the indicator type when you needed by checking the type of list Item.
Or use a dictionary with an Enum key type, the Enum will have each indicator type name and you can easily cast the object to that indicator type instead of checking each item, it will increase the performance.
To check the bases of built-in indicator types you can use Visual Studio.
@amusleh
amusleh
23 May 2021, 21:21
Hi,
You should use a valid redirect URI, its clearly mentioned on WPF demo readme file.
The redirect URI on your application is for API playground, you can't use that, instead use something like: https://ctrader.com/
@amusleh
amusleh
22 May 2021, 17:44
( Updated at: 21 Dec 2023, 09:22 )
Hi,
We have added a Fibonacci Retracement tool and all other Fibonacci patterns on new version of pattern drawing indicator:
In this version you can modify the levels appearance and level percentages.
The new version of pattern drawing indicator and a separate Fibonacci drawing only indicator will be released in upcoming weeks.
@amusleh
amusleh
19 May 2021, 15:51
Hi,
Please check the Pending Order API reference example #4.
To cancel a pending order with specific label you can use PendingOrders collection with Linq.
@amusleh
amusleh
17 May 2021, 10:04
Hi,
You can use OnBar method which is called when a new bar opens with Position Pips property, example:
using cAlgo.API;
namespace cAlgo.Robots
{
[Robot(TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
public class BarPip : Robot
{
[Parameter(DefaultValue = 10)]
public double MinBarPips { get; set; }
protected override void OnBar()
{
if (Positions.Count == 0)
{
var tradeType = Bars.Last(1).Close > Bars.Last(1).Open ? TradeType.Buy : TradeType.Sell;
ExecuteMarketOrder(tradeType, SymbolName, Symbol.VolumeInUnitsMin);
}
else
{
foreach (var position in Positions)
{
if (position.Pips < MinBarPips)
{
ClosePosition(position);
}
}
}
}
}
}
The above cBot will open a position, and when a new bar opens it checks if the position Pips is less than MinBarPips parameter value, if its then it closes the position.
If you need more samples please check the API references or ask a consultant to develop your cBot for you.
@amusleh
amusleh
17 May 2021, 09:56
Hi,
If you are getting Trading Account is not authorized error from server it means you are connected, so there is no issue with heartbeat or your connection, otherwise you will not be able to receive that error.
Your issue is with trading account authorization not connection, you have to send an account authorization request for each trading account you use on a connection, otherwise if you try to send other messages related to a trading account that is not authorized for that connection you will receive that error.
There is also token expiration or refresh that can de-authorize your authorized account, while your account is authorized for a connection and your access token expire or you refresh the access token then you have to re-authorize that account, to guard against this you can use invalid token message, and whenever it happened you can re-authorize the account.
@amusleh
amusleh
10 May 2021, 08:39
Hi,
You have to add the Redirect URI on your Open API application Redirect URIs list first before trying to use the API authentication.
To add the redirect URI go to your applications page: https://connect.spotware.com/apps
Click on edit "Button" of your application and then add your redirect URI.
@amusleh
amusleh
04 May 2021, 11:09
Hi,
You should use the PendingOrders.Filled event, when your sell order is filled the event will be raised and you can do anything you want to after that.
Please check the API references for code examples (Example 5).
@amusleh
amusleh
04 May 2021, 11:06
Hi,
Your event handler and method name doesn't match, here is the working code:
protected override void OnStart()
{
Positions.Closed += PositionsOnClosed;
}
private void PositionsOnClosed(PositionClosedEventArgs args)
{
var position = args.Position;
Print("Position closed with {0} profit", position.GrossProfit);
}
Please check API references for more examples.
You have to learn at least C# basics before starting to write C# code.
@amusleh
amusleh
03 May 2021, 12:53
RE: RE:
victor.major said:
This looks great! Thank you.
One question, why are we declaring the following as a user variable? Is there any benefit to making the timer not refresh every second for example?
[Parameter("Timer Interval (Seconds)", DefaultValue = 1, MinValue = 1)] public int TimerIntervalInSeconds { get; set; }
V.
amusleh said:
Hi,
There are several issues with your code, first you should not put any time based logic inside OnBar method, instead you should use the OnTimer method and start timer on an interval that suits your specific needs.
You should not use TimeInUtc, the position EntryTime is set based on your robot time zone attribute, and you should use Server.Time not Server.TimeInUtc, it only works if your robot time zone is UTC.
Here is an example cBot:
using cAlgo.API; using System; namespace cAlgo.Robots { [Robot(TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)] public class ClosePositionOnTime : Robot { [Parameter("Timer Interval (Seconds)", DefaultValue = 1, MinValue = 1)] public int TimerIntervalInSeconds { get; set; } [Parameter("Trade Type", DefaultValue = TradeType.Buy)] public TradeType TradeType { get; set; } [Parameter("Profit", DefaultValue = 100)] public double Profit { get; set; } [Parameter("Close Time (Minutes)", DefaultValue = 60)] public double CloseTimeInMinutes { get; set; } [Parameter("Label", DefaultValue = "My_cBot")] public string Label { get; set; } protected override void OnStart() { Timer.Start(TimerIntervalInSeconds); } protected override void OnTimer() { var currentTime = Server.Time; foreach (var position in Positions) { // Filter positions if (!string.Equals(position.Label, Label, StringComparison.OrdinalIgnoreCase) || !position.SymbolName.Equals(SymbolName, StringComparison.OrdinalIgnoreCase) || position.TradeType != TradeType) { continue; } // Close if position meet the condition if (position.EntryTime.AddMinutes(CloseTimeInMinutes) >= currentTime && position.NetProfit >= Profit) { ClosePosition(position); } } } } }
Hi,
I did it for showing to you, you can set the timer interval to any value you want to fixed in code.
@amusleh
amusleh
03 May 2021, 12:10
Hi,
There are several issues with your code, first you should not put any time based logic inside OnBar method, instead you should use the OnTimer method and start timer on an interval that suits your specific needs.
You should not use TimeInUtc, the position EntryTime is set based on your robot time zone attribute, and you should use Server.Time not Server.TimeInUtc, it only works if your robot time zone is UTC.
Here is an example cBot:
using cAlgo.API;
using System;
namespace cAlgo.Robots
{
[Robot(TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
public class ClosePositionOnTime : Robot
{
[Parameter("Timer Interval (Seconds)", DefaultValue = 1, MinValue = 1)]
public int TimerIntervalInSeconds { get; set; }
[Parameter("Trade Type", DefaultValue = TradeType.Buy)]
public TradeType TradeType { get; set; }
[Parameter("Profit", DefaultValue = 100)]
public double Profit { get; set; }
[Parameter("Close Time (Minutes)", DefaultValue = 60)]
public double CloseTimeInMinutes { get; set; }
[Parameter("Label", DefaultValue = "My_cBot")]
public string Label { get; set; }
protected override void OnStart()
{
Timer.Start(TimerIntervalInSeconds);
}
protected override void OnTimer()
{
var currentTime = Server.Time;
foreach (var position in Positions)
{
// Filter positions
if (!string.Equals(position.Label, Label, StringComparison.OrdinalIgnoreCase) || !position.SymbolName.Equals(SymbolName, StringComparison.OrdinalIgnoreCase) || position.TradeType != TradeType)
{
continue;
}
// Close if position meet the condition
if (position.EntryTime.AddMinutes(CloseTimeInMinutes) >= currentTime && position.NetProfit >= Profit)
{
ClosePosition(position);
}
}
}
}
}
@amusleh
amusleh
30 May 2021, 10:23
Hi,
For horizontal lines you have to set and handler for Chart.ObjectsAdded/Removed/Updated events.
Check the object that has been added/removed/updated, if its of type horizontal line then save it on a collection like list.
On your cBot OnTick method, keep checking the current symbol latest Bid/Ask prices, if it touched/crossed any of your lines inside the collection then execute your trade, that's very simple.
@amusleh