Topics
Forum Topics not found
Replies
amusleh
04 Oct 2021, 10:50
Hi,
If your Market Range order is partially filled and you want to execute a new order for the not filled part of your order or do something else you can use the PendingOrders.Filled event instead of PendingOrders.Cancelled event:
private void PendingOrders_Filled(PendingOrderFilledEventArgs obj)
{
// if not all volume filled
if (obj.Position.VolumeInUnits != obj.PendingOrder.VolumeInUnits)
{
// Do something
}
}
@amusleh
amusleh
04 Oct 2021, 10:18
RE:
m4trader4 said:
Hi
Sorry for delayed reply.
The scenario:
I place Buy Pending orders #1 with Price 10 with stop limit range 00.00 - 00.40 pips. The order is executed and not filled due to limit range (out of range). As there were no sellers to sell in the limit range ( 00.00 - 00.40), so the order status is cancelled.
With the PendingOrderEvents cancelled event, the details of the order (Qty, SL, TP ) are captured and new marketrange order is executed. So far its good. The Buy Pending Order is executed, the order is unfilled (Cancelled), then improvised with marketrange order and executed (Filled).
There are pending Buy orders which are placed manually/cbot, When these orders are cancelled (Which are not executed) using "X" button in the order tab, the PendingOrderEvents is executed with a cancelled event status. Which should not happen.
My logic or intention is the PendingOrdersEvents.Cancelled should be called only for the executed orders not for "X" button cancelled orders.
Hope i am able to explain better.
Hi,
I still don't understand why the PendingOrdersEvents.Cancelled event should not be triggered when a user manually cancels a pending order?
The order is canceled and the PendingOrdersEvents.Cancelled must be called, it doesn't matter who or how the order got canceled.
If your stop limit order didn't get filled on your specified limit range then it will be canceled, and it will be considered a canceled pending order.
So the event will be triggered whenever a pending order gets canceled, it doesn't matter from which channel (API) the order got canceled.
@amusleh
amusleh
03 Oct 2021, 09:58
Hi,
You should reference all DLL files inside Release zip file you downloaded, then it will work.
I strongly recommend you to use Visual Studio and install the alert library via Nuget.
Visual Studio is free, you can download it from here: Visual Studio - Visual Studio (microsoft.com)
@amusleh
amusleh
01 Oct 2021, 13:41
( Updated at: 01 Oct 2021, 13:43 )
Hi,
You have to calculate each open position used margin, if your account deposit currency is USD you can do that by:
USD / XXX (ex: USD/CAD):
margin = contract size / leverage;
XXX / USD (ex: EUR/USD):
margin = current price * contract size / leverage;
if your account deposit currency is not USD then you have to convert it to that currency by using other FX cross symbols (which will become more complicated).
After you got the total margin used for example buy EURUSD position then you can check if you have enough margin for sell position or not.
Example:
private double GetUsedMargin(string symbolName, TradeType tradeType)
{
var symbol = Symbols.GetSymbol(symbolName);
var positionsCopy = Positions.ToArray();
double usedMargin = 0;
foreach (var position in positionsCopy)
{
if (position.SymbolName.Equals(symbolName, StringComparison.OrdinalIgnoreCase) && position.TradeType == tradeType)
{
usedMargin += symbolName.StartsWith("USD", StringComparison.OrdinalIgnoreCase)
? position.VolumeInUnits / Account.PreciseLeverage
: symbol.Bid * position.VolumeInUnits / Account.PreciseLeverage;
}
}
return usedMargin;
}
The above method will give you the amount of used margin by a symbol buy or sell positions, the symbol must be in XXX/USD or USD/XXX format, otherwise it will not work.
Once you got a symbol buy/sell positions total margin you can use it on your if condition instead of Account.Margin.
@amusleh
amusleh
01 Oct 2021, 11:50
Hi,
For equity loss you don't have to use margin, instead you can calculate the percentage you are in loss by using only account equity and balance:
private void tradeExecution(TradeType type, string sym, string label)
{
var equityLossPercentage = (Account.Equity - Account.Balance) / Account.Balance * 100;
if (autoMode2 && equityLossPercentage >= -10)
{
if (type == TradeType.Buy)
{
double close = lowBar[sym].ClosePrices.LastValue;
double minvolume = Symbols.GetSymbol(sym).VolumeInUnitsMin;
double atr = ATR[sym].Result.LastValue;
double gap = ATR[sym].Result.LastValue * (1 / Symbols.GetSymbol(sym).PipSize);
var tp_1st = Math.Round(gap, 0);
var sl_1st = Math.Round((gap * 20), 0);
automode2PositionCount(sym, TradeType.Buy, close + atr, close - atr);
if (pcount > 0)
{
if (close > pAboveprice && pcountwithin == 0)
ExecuteMarketOrder(TradeType.Buy, sym, minvolume, "EA", 0, 0);
if (close < pBelowprice && pcountwithin == 0)
ExecuteMarketOrder(TradeType.Buy, sym, minvolume * (pcount + 1), "EA", 0, 0);
}
else
{
ExecuteMarketOrder(TradeType.Buy, sym, minvolume, "EA", sl_1st, tp_1st);
}
Print(sym + " : BUY" + " ATR : " + gap + " Count: " + pcount + " Within: " + pcountwithin);
}
if (type == TradeType.Sell)
{
double close = lowBar[sym].ClosePrices.LastValue;
double minvolume = Symbols.GetSymbol(sym).VolumeInUnitsMin;
double atr = ATR[sym].Result.LastValue;
double gap = ATR[sym].Result.LastValue * (1 / Symbols.GetSymbol(sym).PipSize);
var tp_1st = Math.Round(gap, 0);
var sl_1st = Math.Round((gap * 20), 0);
automode2PositionCount(sym, TradeType.Sell, close + atr, close - atr);
if (pcount > 0)
{
if (close > pAboveprice && pcountwithin == 0)
ExecuteMarketOrder(TradeType.Sell, sym, minvolume * (pcount + 1), "EA", 0, 0);
if (close < pBelowprice && pcountwithin == 0)
ExecuteMarketOrder(TradeType.Sell, sym, minvolume, "EA", 0, 0);
}
else
{
ExecuteMarketOrder(TradeType.Sell, sym, minvolume, "EA", sl_1st, tp_1st);
}
Print(sym + " : SELL" + " ATR : " + gap + " Count : " + pcount + " Within : " + pcountwithin);
}
}
else
{
Print(sym + " : Max Equity Drawdown Trade not allowed " + losspercentage);
}
}
For example, your account balance is 1000 and your equity is 900, it means you are down -10%.
@amusleh
amusleh
01 Oct 2021, 09:51
Hi,
You can use this method to get number of RSI touches:
/// <summary>
/// Returns the number of RSI level touches on a specific period
/// </summary>
/// <param name="periods">The past number of bars</param>
/// <param name="level">The RSI level</param>
/// <returns>Number of Touches</returns>
private int GetRsiTouches(int periods, double level)
{
var index = Bars.Count - 1;
var touchCount = 0;
for (int barIndex = index; barIndex > index - periods; barIndex--)
{
if ((level > 0 && rsi.Result[barIndex] >= level && rsi.Result[barIndex - 1] < level) || (level < 0 && rsi.Result[barIndex] <= level && rsi.Result[barIndex - 1] > level))
{
touchCount++;
}
}
return touchCount;
}
@amusleh
amusleh
01 Oct 2021, 09:38
Hi,
I still don't understand your exact issue, the Account.Margin gives you the amount of used margin.
The 116 is the amount of margin you need for a 1:500 leverage account to open a 0.5 lots buy EURUSD position, and the 0.2 lots sell position doesn't cost you any extra margin.
Here is my used margin when I opened the first 0.5 lots buy position:
And here is my used margin after I opened the second sell position:
You see my used margin didn't increased at all, that's the exact value you get from Account.Margin.
So, the sell position doesn't increase your used margin, you are using 10% of your margin, if you want to keep opening positions then set the percentage of margin to 20% not 10%.
@amusleh
amusleh
30 Sep 2021, 11:31
Hi,
There is no doc generator available for proto files in .NET, but you can use this Go proto doc generator: gendoc package - github.com/pseudomuto/protoc-gen-doc - pkg.go.dev
It allows you to generate docs in different formats easily, we also use it to generate the Open API documentation API references.
OpenAPI.NET is a library that allows you to use Open API on your .NET apps, it doesn't generate docs for proto files or Open API.
@amusleh
amusleh
30 Sep 2021, 11:26
Hi,
I checked your code, there is no issue on your margin condition.
Can you just use balance not equity and see if it executes any trade or not.
I think your equity fell below your max margin loss percentage amount, and that stops the bot from opening new positions.
@amusleh
amusleh
29 Sep 2021, 11:43
Hi,
I just tested my posted code on a 2 year historical data back tester, it didn't hanged my PC nor it caused any other issue.
Back to your original code, the issue it not margin calculation, cTrader API Account.Margin value doesn't increase if you open an opposite position, you can test it.
The issue of not opening new positions most probably is caused by your condition that check the buy/sell count.
You are also using OnBar method on your code, which is executed once per each bar open, not on each tick, and that might be the cause because the method will be executed only when a new bar opens.
Try this:
using System;
using System.Linq;
using cAlgo.API;
using cAlgo.API.Indicators;
using cAlgo.API.Internals;
using cAlgo.Indicators;
namespace cAlgo
{
[Robot(TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
public class AdvancedHedgingBot : Robot
{
[Parameter("Volume", DefaultValue = 1000, MinValue = 1, Step = 1)]
public int Volume { get; set; }
private double _Margin;
private int noOfPositions = 4;
private int pips = 2;
protected override void OnStart()
{
_Margin = Account.Balance;
ExecuteMarketOrder(TradeType.Buy, Symbol, Volume, "BUY");
ExecuteMarketOrder(TradeType.Sell, Symbol, Volume, "SELL");
}
protected override void OnTick()
{
foreach (var position in Positions)
{
if (position.Pips > pips)
{
ClosePosition(position);
}
}
if (Positions.Count < noOfPositions)
{
ExecuteMarketOrder(TradeType.Buy, Symbol, Volume, "BUY");
ExecuteMarketOrder(TradeType.Sell, Symbol, Volume, "SELL");
}
int buyCount = 0;
int sellCount = 0;
foreach (var position in Positions)
{
if (position.TradeType == TradeType.Buy)
buyCount++;
if (position.TradeType == TradeType.Sell)
sellCount++;
}
if (Account.Margin / _Margin * 100 <= 10)
{
Volume += 1000;
noOfPositions += 2;
pips++;
ExecuteMarketOrder(TradeType.Buy, Symbol, Volume, "BUY");
ExecuteMarketOrder(TradeType.Sell, Symbol, Volume, "SELL");
}
}
}
}
I removed your condition for buy/sell count check from if statement, you can add them back if you want to.
You don't have to nest if statements like that, you can add multiple conditions on a single if statement one after another:
if (Account.Margin / _Margin * 100 <= 10 && (buyCount == 0 || sellCount == 0))
{
Volume += 1000;
noOfPositions += 2;
pips++;
ExecuteMarketOrder(TradeType.Buy, Symbol, Volume, "BUY");
ExecuteMarketOrder(TradeType.Sell, Symbol, Volume, "SELL");
}
@amusleh
amusleh
29 Sep 2021, 10:18
Hi,
Try this:
using System;
using cAlgo.API;
namespace cAlgo
{
[Indicator(IsOverlay = false, TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
public class NewIndicator : Indicator
{
protected override void Initialize()
{
}
public override void Calculate(int index)
{
if (!IsLastBar) return;
// Returns the min/max of last 10 bars
var minMax = GetMinMax(Bars.OpenTimes[index - 10], Bars.OpenTimes[index]);
Print("Min: {0} | Max: {1}", minMax.Item1, minMax.Item2);
}
/// <summary>
/// Returns the minimum/maximum prices levels during an specific time period
/// </summary>
/// <param name="startTime">Start Time (Inclusive)</param>
/// <param name="endTime">End Time (Inclusive)</param>
/// <returns>Tuple<double, double> (Item1 will be minimum price and Item2 will be maximum price)</returns>
private Tuple<double, double> GetMinMax(DateTime startTime, DateTime endTime)
{
var min = double.MaxValue;
var max = double.MinValue;
for (int barIndex = 0; barIndex < Bars.Count; barIndex++)
{
var bar = Bars[barIndex];
if (bar.OpenTime < startTime || bar.OpenTime > endTime)
{
if (bar.OpenTime > endTime) break;
continue;
}
min = Math.Min(min, bar.Low);
max = Math.Max(max, bar.High);
}
return new Tuple<double, double>(min, max);
}
}
}
You have the full historical bars data of your chart time frame, and you can iterate over it to find highs/lows.
@amusleh
amusleh
29 Sep 2021, 09:30
RE: RE:
ctid3304047 said:
amusleh said:
Hi,
Right now we don't any library for Python or C++, we only have a .NET library.
We will develop more libraries and we will have one for Python in upcoming months.
Open API uses Google Protocol Buffers protocol, its Language agnostic and you can interact with it easily, please check Open API documentation for more detail.
Hi,
is there any progress?
I managed to use Protocol Buffers, however I couldn't authenticate yet with socket...
Trying to use grpc and it is not obvious to me how to send ProtoOAApplicationAuthReq and ProtoOAAccountAuthReq correctly.
Any help would be greatly appreciated
Hi,
We will develop a Python package for Open API, but I can't give you an ETA.
Hopefully it will be released next month.
First you have to create a TCP socket connection with Open API live/demo endpoints, then use the connection to send/receive messages.
We have a guide for it on Open API documentation: Reading/Writing - Open API (spotware.github.io)
@amusleh
amusleh
28 Sep 2021, 09:38
Hi,
You have to define a mathematical relation between those numbers, then you can code it.
Try this:
using System;
using cAlgo.API;
using cAlgo.API.Internals;
namespace cAlgo
{
[Indicator(IsOverlay = true, TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
public class test : Indicator
{
[Parameter("Amount (Pips)", DefaultValue = 21)]
public double AmountInPips { get; set; }
[Parameter("Step (Pips)", DefaultValue = 100)]
public double StepInPips { get; set; }
[Parameter("Min Level (Price)", DefaultValue = 1)]
public double MinLevelInPrice { get; set; }
[Parameter("Max Level (Price)", DefaultValue = 10)]
public double MaxLevelInPrice { get; set; }
protected override void Initialize()
{
AmountInPips *= Symbol.PipSize;
StepInPips *= Symbol.PipSize;
for (var level = MinLevelInPrice; level < MaxLevelInPrice; level += StepInPips)
{
var lineLevel = Math.Round(level + AmountInPips, Symbol.Digits);
Chart.DrawHorizontalLine(lineLevel.ToString(), lineLevel, Color.Red);
// Uncomment the print if you want to check the line levels on your cTrader automate logs tab
//Print(lineLevel);
}
}
public override void Calculate(int index)
{
}
}
}
You might be able to find other better ways to code the same thing witch will be much faster than mine.
@amusleh
amusleh
27 Sep 2021, 17:04
Hi,
The code I posted uses your account live equity and compare it with the amount of used margin, if you want to use your starting account balance as initial value then try this:
using cAlgo.API;
namespace cAlgo
{
[Robot(TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
public class AdvancedHedgingBot : Robot
{
[Parameter("Volume", DefaultValue = 1000, MinValue = 1, Step = 1)]
public int Volume { get; set; }
private int noOfPositions = 4;
private int pips = 2;
private double _balance;
protected override void OnStart()
{
_balance = Account.Balance;
ExecuteMarketOrder(TradeType.Buy, Symbol, Volume, "BUY");
ExecuteMarketOrder(TradeType.Sell, Symbol, Volume, "SELL");
}
protected override void OnTick()
{
foreach (var position in Positions)
{
if (position.Pips > pips)
{
ClosePosition(position);
}
}
if (Positions.Count < noOfPositions)
{
ExecuteMarketOrder(TradeType.Buy, Symbol, Volume, "BUY");
ExecuteMarketOrder(TradeType.Sell, Symbol, Volume, "SELL");
}
int buyCount = 0;
int sellCount = 0;
foreach (var position in Positions)
{
if (position.TradeType == TradeType.Buy)
buyCount++;
if (position.TradeType == TradeType.Sell)
sellCount++;
}
// This will keep opening buy and sell positions unless your margin reach 10%, then it stops
// It opens at most two buy and two sell positions (total 4)
while (Account.Margin / _balance * 100 < 10 && buyCount + sellCount < 4)
{
if (buyCount < 2)
{
buyCount++;
ExecuteMarketOrder(TradeType.Buy, Symbol, Volume, "BUY");
}
if (sellCount < 2)
{
sellCount++;
ExecuteMarketOrder(TradeType.Sell, Symbol, Volume, "SELL");
}
}
}
}
}
@amusleh
amusleh
27 Sep 2021, 10:42
You can use Chart.DrawText:
for (double level = startHun; level <= max + stepHun; level += stepHun)
{
ChartObjects.DrawHorizontalLine("line_2" + level, level, Colors.Blue);
// You can add some distance if you want to by adding some pips value to level
// The x axis value to last bar on chart, you can change it based on your needs
Chart.DrawText("line_2_text" + level, level.ToString(), Chart.LastVisibleBarIndex, level, Color.Blue);
}
@amusleh
amusleh
27 Sep 2021, 10:38
Hi,
Yes, its possible:
using cAlgo.API;
namespace cAlgo
{
[Robot(TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
public class MinEquityBot : Robot
{
[Parameter("Min Equity", DefaultValue = 1000)]
public int MinEquity { get; set; }
protected override void OnTick()
{
if (Account.Equity <= MinEquity)
{
foreach (var position in Positions)
{
ClosePosition(position);
}
}
}
}
}
@amusleh
amusleh
05 Oct 2021, 18:43
Hi,
Positions collection is an IEnumerable, and if you open a new position or close an old one the collection will change.
If collection change while you were iterating over it (with a loop) you will get a collection modified exception and your loop will break.
To protect your bot or indicator from collection modified exception you can create a local copy of positions collection and then loop over it:
@amusleh