
Topics
Replies
PanagiotisCharalampous
03 Jun 2019, 11:01
Hi RayAdam,
Thanks for posting in our forum. I had a look at your indicator but I cannot see any problem. I can see the lines in Range Bar 10 pips. Could you please elaborate?
Best Regards,
Panagiotis
@PanagiotisCharalampous
PanagiotisCharalampous
03 Jun 2019, 10:45
Hi El Antonio,
Can you share the cBot so that we can reproduce?
Best Regards,
Panagiotis
@PanagiotisCharalampous
PanagiotisCharalampous
03 Jun 2019, 10:37
Hi asencanada,
How can we help you?
Best Regards,
Panagiotis
@PanagiotisCharalampous
PanagiotisCharalampous
03 Jun 2019, 10:29
Hi Matt,
The code below should work on the latest version of cTrader
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 BidAsk : Indicator { [Parameter("To Infinite", DefaultValue = true)] public bool ToInfinite { get; set; } [Parameter(DefaultValue = 0)] public int Displacement { get; set; } [Output("Ask", Color = Colors.DodgerBlue, PlotType = PlotType.DiscontinuousLine)] public IndicatorDataSeries SymbolAsk { get; set; } [Output("Bid", Color = Colors.Red, PlotType = PlotType.DiscontinuousLine)] public IndicatorDataSeries SymbolBid { get; set; } protected override void Initialize() { // Initialize and create nested indicators } public override void Calculate(int index) { if (!IsLastBar) return; SymbolBid[index + Displacement - 1] = double.NaN; SymbolAsk[index + Displacement - 1] = double.NaN; for (int i = ToInfinite ? -MarketSeries.Close.Count : Displacement; i < 200; i++) { SymbolBid[index + i] = Symbol.Ask; SymbolAsk[index + i] = Symbol.Bid; } } } }
Best Regards,
Panagiotis
@PanagiotisCharalampous
PanagiotisCharalampous
31 May 2019, 15:14
Hi mpistorius,
At the moment to keep the objects on the charts you need to make them interactive. Here is an example how to make them interactive
var line = Chart.DrawVerticalLine("line", Time, Color.Red); line.IsInteractive = true;
Best Regards,
Panagiotis
@PanagiotisCharalampous
PanagiotisCharalampous
31 May 2019, 14:44
Hi andywhitehi,
Can you please let us know which videos are you referring to?
Best Regards,
Panagiotis
@PanagiotisCharalampous
PanagiotisCharalampous
31 May 2019, 10:47
Hi Max,
I thing I am still missing something since if this was the code you are using then the solution would be as simple as this
private void CloseAllPositions() { foreach (Position p in Positions.Where(p => p.Label == BotLabel).ToArray()) ClosePosition(p); ExecuteMarketOrder(TradeType.Buy, Symbol, Volume, BotLabel, null, 5); }
However I am sure this is not the case :) and this is just an exampe. From what I understand, the positions are closed by TP so you are not sure when did all the positions close and if there are other Closed events coming. So my suggestion is to keep each position you open in a collection (list, dictionary etc) and remove it from the collection as soon as you receive the Closed event for that position. As soon as the collection is empty (meaning all positions closed successfully) you can proceed with sending the new order.
Let me know if this gives you a direction.
Best Regards,
Panagiotis
@PanagiotisCharalampous
PanagiotisCharalampous
31 May 2019, 09:41
Hi Max,
This is not multithreading but event criven programming. Both OnPositionsClosed and OnTick are event which do not depend on each other. My approach would be to trigger the order only when all the positions of the group have closed. However without the cBot code we cannot provide specific guidance as we can only make assumptions about it.
Best Regards,
Panagiotis
@PanagiotisCharalampous
PanagiotisCharalampous
31 May 2019, 09:28
Hi kanapon,
Yes that is correct, sorry for the typo :)
Best Regards,
Panagiotis
@PanagiotisCharalampous
PanagiotisCharalampous
30 May 2019, 14:23
Hi aerich48,
We had a look at this and it seems that at the time you sent the message above you were already logged in, this is why you did not receive a response. Can you please check your implementation? If you already have sessions established then you need to log out first before you can login again.
Best Regards,
Panagiotis
@PanagiotisCharalampous
PanagiotisCharalampous
30 May 2019, 14:08
Hi ramonsgarcia,
Thanks for posting in our forum. The MACD Histogram is plotting the MACD line find in MACD Crossover as a histogram and not the Histofram line of the MACD Crossover.
Best Regards,
Panagiotis
@PanagiotisCharalampous
PanagiotisCharalampous
30 May 2019, 11:59
Hi aerich48,
The fact that the nearest proxy is changing in cTrader should not affect your connectivity with other proxies. If it is possible please send us at community@spotware.com the exact message that received an empty response with its timestamp and the proxy to which it was sent so that we can investigate what happened.
Best Regards,
Panagiotis
@PanagiotisCharalampous
PanagiotisCharalampous
30 May 2019, 11:50
Hi Accelerate,
Backtesting data is created from the broker's price feed. Since brokers have different price feeds, you cannot expect that the backtesting data will match. If you still believe there is an issue, please contact your broker.
Best Regards,
Panagiotis
@PanagiotisCharalampous
PanagiotisCharalampous
30 May 2019, 09:37
Hi nelson.pmf.sc,
Try the below
if (Positions.Count(x => x.Label == "EUR/USD C") < 20)
Best Regards,
Panagiotis
@PanagiotisCharalampous
PanagiotisCharalampous
30 May 2019, 09:32
Hi nmaxcom,
Can you post the cBot code and explain your calim that "an equity drawdown that never happened"?
Best Regards,
Panagiotis
@PanagiotisCharalampous
PanagiotisCharalampous
29 May 2019, 17:43
Hi francescoxio,
Thanks for posting in our forum. To delete your account you need to contact ICMarkets.
Best Regards,
Panagiotis
@PanagiotisCharalampous
PanagiotisCharalampous
29 May 2019, 11:52
Hi kanapon,
Can you try the cBot below and let me know if this is what you need?
// //+------------------------------------------------------------------+ //| Smart Grid | //| Copyright 2014, MD SAIF | //| http://www.facebook.com/cls.fx | //+------------------------------------------------------------------+ //-Grid trader cBot based on Bar-Time & Trend. For range market & 15 minute TimeFrame is best. using System; using cAlgo.API; namespace cAlgo { [Robot(TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)] public class SmartGrid : Robot { private bool _accountIsOutOfMoney; private int _openTradeResult; private readonly string Label = "SmartGrid2"; private DateTime _lastBuyTradeTime; private DateTime _lastSellTradeTime; [Parameter("Buy", DefaultValue = true)] public bool Buy { get; set; } [Parameter("Sell", DefaultValue = true)] public bool Sell { get; set; } [Parameter("Pip Step", DefaultValue = 10, MinValue = 1)] public int PipStep { get; set; } [Parameter("First Volume", DefaultValue = 1000, MinValue = 1000, Step = 1000)] public int FirstVolume { get; set; } [Parameter("Volume Exponent", DefaultValue = 1.0, MinValue = 0.1, MaxValue = 5.0)] public double VolumeExponent { get; set; } [Parameter("Max Spread", DefaultValue = 3.0)] public double MaxSpread { get; set; } [Parameter("Average TP", DefaultValue = 3, MinValue = 1)] public int AverageTakeProfit { get; set; } private double CurrentSpread { get { return (Symbol.Ask - Symbol.Bid) / Symbol.PipSize; } } protected override void OnStart() { } protected override void OnTick() { if (CountOfTradesOfType(TradeType.Buy) > 0) AdjustBuyPositionTakeProfits(CalculateAveragePositionPrice(TradeType.Buy), AverageTakeProfit); if (CountOfTradesOfType(TradeType.Sell) > 0) AdjustSellPositionTakeProfits(CalculateAveragePositionPrice(TradeType.Sell), AverageTakeProfit); if (CurrentSpread <= MaxSpread && !_accountIsOutOfMoney) ProcessTrades(); if (!this.IsBacktesting) DisplayStatusOnChart(); } protected override void OnError(Error error) { if (error.Code == ErrorCode.NoMoney) { _accountIsOutOfMoney = true; Print("opening stopped because: not enough money"); } } protected override void OnBar() { RefreshData(); } protected override void OnStop() { // ChartObjects.RemoveAllObjects(); Chart.RemoveAllObjects(); } private void ProcessTrades() { if (Buy && CountOfTradesOfType(TradeType.Buy) == 0 && MarketSeries.Close.Last(1) > MarketSeries.Close.Last(2)) { _openTradeResult = OrderSend(TradeType.Buy, LimitVolume(FirstVolume)); if (_openTradeResult > 0) _lastBuyTradeTime = MarketSeries.OpenTime.Last(0); else Print("First BUY openning error at: ", Symbol.Ask, "Error Type: ", LastResult.Error); } if (Sell && CountOfTradesOfType(TradeType.Sell) == 0 && MarketSeries.Close.Last(2) > MarketSeries.Close.Last(1)) { _openTradeResult = OrderSend(TradeType.Sell, LimitVolume(FirstVolume)); if (_openTradeResult > 0) _lastSellTradeTime = MarketSeries.OpenTime.Last(0); else Print("First SELL opening error at: ", Symbol.Bid, "Error Type: ", LastResult.Error); } if (CountOfTradesOfType(TradeType.Buy) > 0 && Buy) { if (Math.Round(Symbol.Ask, Symbol.Digits) < Math.Round(FindLowestPositionPrice(TradeType.Buy) - PipStep * Symbol.PipSize, Symbol.Digits) && _lastBuyTradeTime != MarketSeries.OpenTime.Last(0)) { var calculatedVolume = CalculateVolume(TradeType.Buy); _openTradeResult = OrderSend(TradeType.Buy, LimitVolume(calculatedVolume)); if (_openTradeResult > 0) _lastBuyTradeTime = MarketSeries.OpenTime.Last(0); else Print("Next BUY opening error at: ", Symbol.Ask, "Error Type: ", LastResult.Error); } } if (CountOfTradesOfType(TradeType.Sell) > 0 && Buy) { if (Math.Round(Symbol.Bid, Symbol.Digits) > Math.Round(FindHighestPositionPrice(TradeType.Sell) + PipStep * Symbol.PipSize, Symbol.Digits) && _lastSellTradeTime != MarketSeries.OpenTime.Last(0)) { var calculatedVolume = CalculateVolume(TradeType.Sell); _openTradeResult = OrderSend(TradeType.Sell, LimitVolume(calculatedVolume)); if (_openTradeResult > 0) _lastSellTradeTime = MarketSeries.OpenTime.Last(0); else Print("Next SELL opening error at: ", Symbol.Bid, "Error Type: ", LastResult.Error); } } } private int OrderSend(TradeType tradeType, double volumeToUse) { var returnResult = 0; if (volumeToUse > 0) { var result = ExecuteMarketOrder(tradeType, Symbol, volumeToUse, Label, 0, 0, 0, "smart_grid"); if (result.IsSuccessful) { Print(tradeType, "Opened at: ", result.Position.EntryPrice); returnResult = 1; } else Print(tradeType, "Openning Error: ", result.Error); } else Print("Volume calculation error: Calculated Volume is: ", volumeToUse); return returnResult; } private void AdjustBuyPositionTakeProfits(double averageBuyPositionPrice, int averageTakeProfit) { foreach (var buyPosition in Positions) { if (buyPosition.Label == Label && buyPosition.SymbolCode == Symbol.Code) { if (buyPosition.TradeType == TradeType.Buy) { double? calculatedTakeProfit = Math.Round(averageBuyPositionPrice + averageTakeProfit * Symbol.PipSize, Symbol.Digits); if (buyPosition.TakeProfit != calculatedTakeProfit) ModifyPosition(buyPosition, buyPosition.StopLoss, calculatedTakeProfit); } } } } private void AdjustSellPositionTakeProfits(double averageSellPositionPrice, int averageTakeProfit) { foreach (var sellPosition in Positions) { if (sellPosition.Label == Label && sellPosition.SymbolCode == Symbol.Code) { if (sellPosition.TradeType == TradeType.Sell) { double? calculatedTakeProfit = Math.Round(averageSellPositionPrice - averageTakeProfit * Symbol.PipSize, Symbol.Digits); if (sellPosition.TakeProfit != calculatedTakeProfit) ModifyPosition(sellPosition, sellPosition.StopLoss, calculatedTakeProfit); } } } } private void DisplayStatusOnChart() { if (CountOfTradesOfType(TradeType.Buy) > 1) { var y = CalculateAveragePositionPrice(TradeType.Buy); // ChartObjects.DrawHorizontalLine("bpoint", y, Colors.Yellow, 2, LineStyle.Dots); Chart.DrawHorizontalLine("bpoint", y, Color.Yellow, 2, LineStyle.Dots); } else //ChartObjects.RemoveObject("bpoint"); Chart.RemoveObject("bpoint"); if (CountOfTradesOfType(TradeType.Sell) > 1) { var z = CalculateAveragePositionPrice(TradeType.Sell); //ChartObjects.DrawHorizontalLine("spoint", z, Colors.HotPink, 2, LineStyle.Dots); Chart.DrawHorizontalLine("spoint", z, Color.HotPink, 2, LineStyle.Dots); } else //ChartObjects.RemoveObject("spoint"); Chart.RemoveObject("spoint"); //ChartObjects.DrawText("pan", GenerateStatusText(), StaticPosition.TopLeft, Colors.Tomato); Chart.DrawStaticText("pan", GenerateStatusText(), VerticalAlignment.Top, HorizontalAlignment.Left, Color.Tomato); } private string GenerateStatusText() { var statusText = ""; var buyPositions = ""; var sellPositions = ""; var spread = ""; var buyDistance = ""; var sellDistance = ""; spread = "\nSpread = " + Math.Round(CurrentSpread, 1); buyPositions = "\nBuy Positions = " + CountOfTradesOfType(TradeType.Buy); sellPositions = "\nSell Positions = " + CountOfTradesOfType(TradeType.Sell); if (CountOfTradesOfType(TradeType.Buy) > 0) { var averageBuyFromCurrent = Math.Round((CalculateAveragePositionPrice(TradeType.Buy) - Symbol.Bid) / Symbol.PipSize, 1); buyDistance = "\nBuy Target Away = " + averageBuyFromCurrent; } if (CountOfTradesOfType(TradeType.Sell) > 0) { var averageSellFromCurrent = Math.Round((Symbol.Ask - CalculateAveragePositionPrice(TradeType.Sell)) / Symbol.PipSize, 1); sellDistance = "\nSell Target Away = " + averageSellFromCurrent; } if (CurrentSpread > MaxSpread) statusText = "MAX SPREAD EXCEED"; else statusText = "Smart Grid" + buyPositions + spread + sellPositions + buyDistance + sellDistance; return (statusText); } private int CountOfTradesOfType(TradeType tradeType) { var tradeCount = 0; foreach (var position in Positions) { if (position.Label == Label && position.SymbolCode == Symbol.Code) { if (position.TradeType == tradeType) tradeCount++; } } return tradeCount; } private double CalculateAveragePositionPrice(TradeType tradeType) { double result = 0; double averagePrice = 0; double count = 0; foreach (var position in Positions) { if (position.Label == Label && position.SymbolCode == Symbol.Code) { if (position.TradeType == tradeType) { averagePrice += position.EntryPrice * position.VolumeInUnits; count += position.VolumeInUnits; } } } if (averagePrice > 0 && count > 0) result = Math.Round(averagePrice / count, Symbol.Digits); return result; } private double FindLowestPositionPrice(TradeType tradeType) { double lowestPrice = 0; foreach (var position in Positions) { if (position.Label == Label && position.SymbolCode == Symbol.Code) { if (position.TradeType == tradeType) { if (lowestPrice == 0) { lowestPrice = position.EntryPrice; continue; } if (position.EntryPrice < lowestPrice) lowestPrice = position.EntryPrice; } } } return lowestPrice; } private double FindHighestPositionPrice(TradeType tradeType) { double highestPrice = 0; foreach (var position in Positions) { if (position.Label == Label && position.SymbolCode == Symbol.Code) { if (position.TradeType == tradeType) { if (highestPrice == 0) { highestPrice = position.EntryPrice; continue; } if (position.EntryPrice > highestPrice) highestPrice = position.EntryPrice; } } } return highestPrice; } private double FindPriceOfMostRecentPositionId(TradeType tradeType) { double price = 0; var highestPositionId = 0; foreach (var position in Positions) { if (position.Label == Label && position.SymbolCode == Symbol.Code) { if (position.TradeType == tradeType) { if (highestPositionId == 0 || highestPositionId > position.Id) { price = position.EntryPrice; highestPositionId = position.Id; } } } } return price; } private double GetMostRecentPositionVolume(TradeType tradeType) { double mostRecentVolume = 0; var highestPositionId = 0; foreach (var position in Positions) { if (position.Label == Label && position.SymbolCode == Symbol.Code) { if (position.TradeType == tradeType) { if (highestPositionId == 0 || highestPositionId > position.Id) { mostRecentVolume = position.VolumeInUnits; highestPositionId = position.Id; } } } } return mostRecentVolume; } private int CountNumberOfPositionsOfType(TradeType tradeType) { var mostRecentPrice = FindPriceOfMostRecentPositionId(tradeType); var numberOfPositionsOfType = 0; foreach (var position in Positions) { if (position.Label == Label && position.SymbolCode == Symbol.Code) { if (position.TradeType == tradeType && tradeType == TradeType.Buy) { if (Math.Round(position.EntryPrice, Symbol.Digits) <= Math.Round(mostRecentPrice, Symbol.Digits)) numberOfPositionsOfType++; } if (position.TradeType == tradeType && tradeType == TradeType.Sell) { if (Math.Round(position.EntryPrice, Symbol.Digits) >= Math.Round(mostRecentPrice, Symbol.Digits)) numberOfPositionsOfType++; } } } return (numberOfPositionsOfType); } private double CalculateVolume(TradeType tradeType) { var numberOfPositions = CountNumberOfPositionsOfType(tradeType); var mostRecentVolume = GetMostRecentPositionVolume(tradeType); var calculatedVolume = Symbol.NormalizeVolumeInUnits(mostRecentVolume * Math.Pow(VolumeExponent, numberOfPositions)); return (calculatedVolume); } private double LimitVolume(double volumeIn) { var symbolVolumeMin = Symbol.VolumeInUnitsMin; var symbolVolumeMax = Symbol.VolumeInUnitsMax; var result = volumeIn; if (result < symbolVolumeMin) result = symbolVolumeMin; if (result > symbolVolumeMax) result = symbolVolumeMax; return (result); } } }
Best Regards,
Panagiotis
@PanagiotisCharalampous
PanagiotisCharalampous
29 May 2019, 10:50
Hi kanapon,
Thanks for posting in our forum. It seems that this parameter affects only the placement of the first order. If there are positions opened, then it is ignored.
Best Regards,
Panagiotis
@PanagiotisCharalampous
PanagiotisCharalampous
29 May 2019, 09:43
Hi maustofx,
Thank you for posting in our forum. This functionality is by design. Objects are saved for the chart, not for the timeframe for the symbol.
Best Regards,
Panagiotis
@PanagiotisCharalampous
PanagiotisCharalampous
03 Jun 2019, 11:51
Hi John,
If you want to stop following a strategy, just click on the menu button on the right of the subaccount and choose "Stop Copying". Hi you want to hide subaccounts that have been stopped, use the cog button on the top of the accounts tree and uncheck "Stopped".
Best Regards,
Panagiotis
@PanagiotisCharalampous