Description
Smart Grid cBot will open first position based on trend. Next positions will be added using 'PipStep' parameter. Dynamic Volume Exponent & 1 trade per 1 bar to minimize draw-down risk. Follow trend direction manually & open Buy Sell your choice.
//+------------------------------------------------------------------+
//| 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 System.Linq;
using cAlgo.API;
namespace cAlgo
{
[Robot(TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
public class SmartGrid : Robot
{
[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 AverageTP { get; set; }
private string Label = "cls";
private Position position;
private DateTime tc_31;
private DateTime tc_32;
private int gi_21;
private double sp_d;
private bool is_12 = true;
private bool cStop = false;
protected override void OnStart()
{
}
protected override void OnTick()
{
sp_d = (Symbol.Ask - Symbol.Bid) / Symbol.PipSize;
if (o_tm(TradeType.Buy) > 0)
f0_86(pnt_12(TradeType.Buy), AverageTP);
if (o_tm(TradeType.Sell) > 0)
f0_88(pnt_12(TradeType.Sell), AverageTP);
if (MaxSpread >= sp_d && !cStop)
Open_24();
RCN();
}
protected override void OnError(Error error)
{
if (error.Code == ErrorCode.NoMoney)
{
cStop = true;
Print("openning stopped because: not enough money");
}
}
protected override void OnBar()
{
RefreshData();
}
protected override void OnStop()
{
ChartObjects.RemoveAllObjects();
}
private void Open_24()
{
if (is_12)
{
if (Buy && o_tm(TradeType.Buy) == 0 && MarketSeries.Close.Last(1) > MarketSeries.Close.Last(2))
{
gi_21 = OrderSend(TradeType.Buy, fer(FirstVolume, 0));
if (gi_21 > 0)
tc_31 = MarketSeries.OpenTime.Last(0);
else
Print("First BUY openning error at: ", Symbol.Ask, "Error Type: ", LastResult.Error);
}
if (Sell && o_tm(TradeType.Sell) == 0 && MarketSeries.Close.Last(2) > MarketSeries.Close.Last(1))
{
gi_21 = OrderSend(TradeType.Sell, fer(FirstVolume, 0));
if (gi_21 > 0)
tc_32 = MarketSeries.OpenTime.Last(0);
else
Print("First SELL openning error at: ", Symbol.Bid, "Error Type: ", LastResult.Error);
}
}
N_28();
}
private void N_28()
{
if (o_tm(TradeType.Buy) > 0)
{
if (Math.Round(Symbol.Ask, Symbol.Digits) < Math.Round(D_TD(TradeType.Buy) - PipStep * Symbol.PipSize, Symbol.Digits) && tc_31 != MarketSeries.OpenTime.Last(0))
{
long gl_57 = n_lt(TradeType.Buy);
gi_21 = OrderSend(TradeType.Buy, fer(gl_57, 2));
if (gi_21 > 0)
tc_31 = MarketSeries.OpenTime.Last(0);
else
Print("Next BUY openning error at: ", Symbol.Ask, "Error Type: ", LastResult.Error);
}
}
if (o_tm(TradeType.Sell) > 0)
{
if (Math.Round(Symbol.Bid, Symbol.Digits) > Math.Round(U_TD(TradeType.Sell) + PipStep * Symbol.PipSize, Symbol.Digits))
{
long gl_59 = n_lt(TradeType.Sell);
gi_21 = OrderSend(TradeType.Sell, fer(gl_59, 2));
if (gi_21 > 0)
tc_32 = MarketSeries.OpenTime.Last(0);
else
Print("Next SELL openning error at: ", Symbol.Bid, "Error Type: ", LastResult.Error);
}
}
}
private int OrderSend(TradeType TrdTp, long iVol)
{
int cd_8 = 0;
if (iVol > 0)
{
TradeResult result = ExecuteMarketOrder(TrdTp, Symbol, iVol, Label, 0, 0, 0, "smart_grid");
if (result.IsSuccessful)
{
Print(TrdTp, "Opened at: ", result.Position.EntryPrice);
cd_8 = 1;
}
else
Print(TrdTp, "Openning Error: ", result.Error);
}
else
Print("Volume calculation error: Calculated Volume is: ", iVol);
return cd_8;
}
private void f0_86(double ai_4, int ad_8)
{
foreach (var position in Positions)
{
if (position.Label == Label && position.SymbolCode == Symbol.Code)
{
if (position.TradeType == TradeType.Buy)
{
double? li_16 = Math.Round(ai_4 + ad_8 * Symbol.PipSize, Symbol.Digits);
if (position.TakeProfit != li_16)
ModifyPosition(position, position.StopLoss, li_16);
}
}
}
}
private void f0_88(double ai_4, int ad_8)
{
foreach (var position in Positions)
{
if (position.Label == Label && position.SymbolCode == Symbol.Code)
{
if (position.TradeType == TradeType.Sell)
{
double? li_16 = Math.Round(ai_4 - ad_8 * Symbol.PipSize, Symbol.Digits);
if (position.TakeProfit != li_16)
ModifyPosition(position, position.StopLoss, li_16);
}
}
}
}
private void RCN()
{
if (o_tm(TradeType.Buy) > 1)
{
double y = pnt_12(TradeType.Buy);
ChartObjects.DrawHorizontalLine("bpoint", y, Colors.Yellow, 2, LineStyle.Dots);
}
else
ChartObjects.RemoveObject("bpoint");
if (o_tm(TradeType.Sell) > 1)
{
double z = pnt_12(TradeType.Sell);
ChartObjects.DrawHorizontalLine("spoint", z, Colors.HotPink, 2, LineStyle.Dots);
}
else
ChartObjects.RemoveObject("spoint");
ChartObjects.DrawText("pan", A_cmt_calc(), StaticPosition.TopLeft, Colors.Tomato);
}
private string A_cmt_calc()
{
string gc_78 = "";
string wn_7 = "";
string wn_8 = "";
string sp_4 = "";
string ppb = "";
string lpb = "";
string nb_6 = "";
double dn_7 = 0;
double dn_9 = 0;
sp_4 = "\nSpread = " + Math.Round(sp_d, 1);
nb_6 = "\nwww.facebook.com/cls.fx\n";
if (dn_7 > 0)
wn_7 = "\nBuy Positions = " + o_tm(TradeType.Buy);
if (dn_9 > 0)
wn_8 = "\nSell Positions = " + o_tm(TradeType.Sell);
if (o_tm(TradeType.Buy) > 0)
{
double igl = Math.Round((pnt_12(TradeType.Buy) - Symbol.Bid) / Symbol.PipSize, 1);
ppb = "\nBuy Target Away = " + igl;
}
if (o_tm(TradeType.Sell) > 0)
{
double osl = Math.Round((Symbol.Ask - pnt_12(TradeType.Sell)) / Symbol.PipSize, 1);
lpb = "\nSell Target Away = " + osl;
}
if (sp_d > MaxSpread)
gc_78 = "MAX SPREAD EXCEED";
else
gc_78 = "Smart Grid" + nb_6 + wn_7 + sp_4 + wn_8 + ppb + lpb;
return (gc_78);
}
private int cnt_16()
{
int ASide = 0;
for (int i = Positions.Count - 1; i >= 0; i--)
{
position = Positions[i];
if (position.Label == Label && position.SymbolCode == Symbol.Code)
ASide++;
}
return ASide;
}
private int o_tm(TradeType TrdTp)
{
int TSide = 0;
for (int i = Positions.Count - 1; i >= 0; i--)
{
position = Positions[i];
if (position.Label == Label && position.SymbolCode == Symbol.Code)
{
if (position.TradeType == TrdTp)
TSide++;
}
}
return TSide;
}
private double pnt_12(TradeType TrdTp)
{
double Result = 0;
double AveragePrice = 0;
long Count = 0;
for (int i = Positions.Count - 1; i >= 0; i--)
{
position = Positions[i];
if (position.Label == Label && position.SymbolCode == Symbol.Code)
{
if (position.TradeType == TrdTp)
{
AveragePrice += position.EntryPrice * position.Volume;
Count += position.Volume;
}
}
}
if (AveragePrice > 0 && Count > 0)
Result = Math.Round(AveragePrice / Count, Symbol.Digits);
return Result;
}
private double D_TD(TradeType TrdTp)
{
double D_TD = 0;
for (int i = Positions.Count - 1; i >= 0; i--)
{
position = Positions[i];
if (position.Label == Label && position.SymbolCode == Symbol.Code)
{
if (position.TradeType == TrdTp)
{
if (D_TD == 0)
{
D_TD = position.EntryPrice;
continue;
}
if (position.EntryPrice < D_TD)
D_TD = position.EntryPrice;
}
}
}
return D_TD;
}
private double U_TD(TradeType TrdTp)
{
double U_TD = 0;
for (int i = Positions.Count - 1; i >= 0; i--)
{
position = Positions[i];
if (position.Label == Label && position.SymbolCode == Symbol.Code)
{
if (position.TradeType == TrdTp)
{
if (U_TD == 0)
{
U_TD = position.EntryPrice;
continue;
}
if (position.EntryPrice > U_TD)
U_TD = position.EntryPrice;
}
}
}
return U_TD;
}
private double f_tk(TradeType TrdTp)
{
double prc_4 = 0;
int tk_4 = 0;
for (int i = Positions.Count - 1; i >= 0; i--)
{
position = Positions[i];
if (position.Label == Label && position.SymbolCode == Symbol.Code)
{
if (position.TradeType == TrdTp)
{
if (tk_4 == 0 || tk_4 > position.Id)
{
prc_4 = position.EntryPrice;
tk_4 = position.Id;
}
}
}
}
return prc_4;
}
private long lt_8(TradeType TrdTp)
{
long lot_4 = 0;
int tk_4 = 0;
for (int i = Positions.Count - 1; i >= 0; i--)
{
position = Positions[i];
if (position.Label == Label && position.SymbolCode == Symbol.Code)
{
if (position.TradeType == TrdTp)
{
if (tk_4 == 0 || tk_4 > position.Id)
{
lot_4 = position.Volume;
tk_4 = position.Id;
}
}
}
}
return lot_4;
}
private long clt(TradeType TrdTp)
{
long Result = 0;
for (int i = Positions.Count - 1; i >= 0; i--)
{
position = Positions[i];
if (position.Label == Label && position.SymbolCode == Symbol.Code)
{
if (position.TradeType == TrdTp)
Result += position.Volume;
}
}
return Result;
}
private int Grd_Ex(TradeType ai_0, TradeType ci_0)
{
double prc_4 = f_tk(ci_0);
int tk_4 = 0;
for (int i = Positions.Count - 1; i >= 0; i--)
{
position = Positions[i];
if (position.Label == Label && position.SymbolCode == Symbol.Code)
{
if (position.TradeType == ai_0 && ai_0 == TradeType.Buy)
{
if (Math.Round(position.EntryPrice, Symbol.Digits) <= Math.Round(prc_4, Symbol.Digits))
tk_4++;
}
if (position.TradeType == ai_0 && ai_0 == TradeType.Sell)
{
if (Math.Round(position.EntryPrice, Symbol.Digits) >= Math.Round(prc_4, Symbol.Digits))
tk_4++;
}
}
}
return (tk_4);
}
private long n_lt(TradeType ca_8)
{
int ic_g = Grd_Ex(ca_8, ca_8);
long gi_c = lt_8(ca_8);
long ld_4 = Symbol.NormalizeVolume(gi_c * Math.Pow(VolumeExponent, ic_g));
return (ld_4);
}
private long fer(long ic_9, int bk_4)
{
long ga_i = Symbol.VolumeMin;
long gd_i = Symbol.VolumeStep;
long dc_i = Symbol.VolumeMax;
long ic_8 = ic_9;
if (ic_8 < ga_i)
ic_8 = ga_i;
if (ic_8 > dc_i)
ic_8 = dc_i;
return (ic_8);
}
}
}
SaifBD
Joined on 05.01.2014
- Distribution: Free
- Language: C#
- Trading platform: cTrader Automate
- File name: Smart Grid.algo
- Rating: 4
- Installs: 15430
- Modified: 13/10/2021 09:54
Comments
Thanks for the gift,
I need to know, if I run this cBot live on a chart interval and the I changed the interval to a another chart interval. Would the trading character gets effected to the new interval?
Thank you
Just BS: You have to check the bot all the time. Opening new buys all the time, even with buys and sells set to off in parameters. Doesn't take long to margin call. Very sad. If the settings would work like they do it would be very good and profitable..
What I need to change in the code for to ensure that when does it touch the TP if I want it to stop opening new positions?
Thanks for the helpful sharing. I want to use this robot in a semi-automatic way. How does it stop automatically when taking a profit? Look forward to hearing from the coder
someone can help me set up the bot for a balance of 150 euros???
Hi.
Mod SmartGrid:
https://ctrader.com/algos/cbots/show/876
up 07.2020
SellSmartGrid - Only - Sell trend (parametr Buy is ignoring) with MA and one way trend LimitStop Sell H1 H4 - only Sell trend backtest date.
https://ctrader.com/forum/calgo-support/22008?page=1
up 07.2020
What are your ideas for improving the code after testing - for Sell trend in xauusd, xagusd, majors etc ?
SellSmartGrid - improving ?!
How 1. cTrader demo to live ctrader, mt4/mt5 Trade Copier ?
How 2. mt4/mt5 demo to live ctrader, mt4/mt5 Trade Copier ?
been away for a while! sure, we can develop something together!
One way trend Sell - SmartGrid MA LimitStop Sell trend. For Gold sell trend. What are your ideas for improving the code after testing?
https://ctrader.com/forum/calgo-support/22008
Hi.
V4 with SMA, but:
1. What wrrong ?
Bot now open buy and sell ?!
sell is false ?!
defaultvalue is ignore ?
How fix ?
2. How put parametrs ?
[Parameter("Maximum open buy position?", Group = "Basic Setup", DefaultValue = 5, MinValue = 0)]
public int MaxOpenBuy { get; set; }
[Parameter("Maximum open Sell position?", Group = "Basic Setup", DefaultValue = 5, MinValue = 0)]
public int MaxOpenSell { get; set; }
More forum:
https://ctrader.com/forum/calgo-support/16641?page=1#7
//+------------------------------------------------------------------+ //| 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; using cAlgo.API.Indicators; using cAlgo.API.Internals; using cAlgo.Indicators; namespace cAlgo { [Robot(TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)] public class oSGMABuy : Robot { private bool _accountIsOutOfMoney; private int _openTradeResult; private readonly string Label = "SmartPBuy"; private DateTime _lastBuyTradeTime; private DateTime _lastSellTradeTime; [Parameter("Source SMA_AO")] public DataSeries Source_SMA { get; set; } [Parameter("Buy", DefaultValue = true)] public bool Buy { get; set; } [Parameter("Sell", DefaultValue = false)] public bool Sell { get; set; } [Parameter("Pip Step", DefaultValue = 20, MinValue = 1)] public int PipStep { get; set; } [Parameter("First Volume", DefaultValue = 10000, 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 = 100, MinValue = 1)] public int AverageTakeProfit { get; set; } [Parameter("Stop Loss", DefaultValue = 0)] public int StopLoss { get; set; } private double CurrentSpread { get { return (Symbol.Ask - Symbol.Bid) / Symbol.PipSize; } } private SimpleMovingAverage _SMA_slow; private SimpleMovingAverage _SMA_Fast; protected override void OnStart() { } protected override void OnTick() { _SMA_slow = Indicators.SimpleMovingAverage(Source_SMA, 200); _SMA_Fast = Indicators.SimpleMovingAverage(Source_SMA, 50); if (_SMA_slow.Result.LastValue > _SMA_Fast.Result.LastValue && _SMA_slow.Result.LastValue > Symbol.Bid) { Buy = false; Sell = true; ChartObjects.DrawText("Sell", ("Vender"), StaticPosition.TopLeft, Colors.AliceBlue); } if (_SMA_slow.Result.LastValue < _SMA_Fast.Result.LastValue && _SMA_slow.Result.LastValue < Symbol.Ask) { Buy = true; Sell = false; ChartObjects.DrawText("buy", ("Comprar"), StaticPosition.TopLeft, Colors.AliceBlue); } 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(); } 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) { 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) { 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, long volumeToUse) { var returnResult = 0; if (volumeToUse > 0) { var result = ExecuteMarketOrder(tradeType, Symbol, volumeToUse, Label, StopLoss, 0, 0, "smart_grid"); if (result.IsSuccessful) { Print(tradeType, "Opened at: ", result.Position.EntryPrice, result.Position.StopLoss); 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); } else ChartObjects.RemoveObject("bpoint"); if (CountOfTradesOfType(TradeType.Sell) > 1) { var z = CalculateAveragePositionPrice(TradeType.Sell); ChartObjects.DrawHorizontalLine("spoint", z, Colors.HotPink, 2, LineStyle.Dots); } else ChartObjects.RemoveObject("spoint"); ChartObjects.DrawText("pan", GenerateStatusText(), StaticPosition.TopLeft, Colors.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; long count = 0; foreach (var position in Positions) { if (position.Label == Label && position.SymbolCode == Symbol.Code) { if (position.TradeType == tradeType) { averagePrice += position.EntryPrice * position.Volume; count += position.Volume; } } } 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 long GetMostRecentPositionVolume(TradeType tradeType) { long 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.Volume; 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 long CalculateVolume(TradeType tradeType) { var numberOfPositions = CountNumberOfPositionsOfType(tradeType); var mostRecentVolume = GetMostRecentPositionVolume(tradeType); var calculatedVolume = Symbol.NormalizeVolume(mostRecentVolume * Math.Pow(VolumeExponent, numberOfPositions)); return (calculatedVolume); } private long LimitVolume(long volumeIn) { var symbolVolumeMin = Symbol.VolumeMin; var symbolVolumeMax = Symbol.VolumeMax; var result = volumeIn; if (result < symbolVolumeMin) result = symbolVolumeMin; if (result > symbolVolumeMax) result = symbolVolumeMax; return (result); } } }
[Parameter("Sell", DefaultValue = false)] public bool Sell { get; set; }
Hi.
What wrrong.
Bot now open buy and sell ?!
sell is false ?!
defaultvalue is ignore ?
How fix ?
how put parametrs ?
[Parameter("Maximum open buy position?", Group = "Basic Setup", DefaultValue = 5, MinValue = 0)]
public int MaxOpenBuy { get; set; }
[Parameter("Maximum open Sell position?", Group = "Basic Setup", DefaultValue = 5, MinValue = 0)]
public int MaxOpenSell { get; set; }
More forum:
https://ctrader.com/forum/calgo-support/16641?page=1#7
V4 with SMA, but:
//+------------------------------------------------------------------+ //| 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; using cAlgo.API.Indicators; using cAlgo.API.Internals; using cAlgo.Indicators; namespace cAlgo { [Robot(TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)] public class oSGMABuy : Robot { private bool _accountIsOutOfMoney; private int _openTradeResult; private readonly string Label = "SmartPBuy"; private DateTime _lastBuyTradeTime; private DateTime _lastSellTradeTime; [Parameter("Source SMA_AO")] public DataSeries Source_SMA { get; set; } [Parameter("Buy", DefaultValue = true)] public bool Buy { get; set; } [Parameter("Sell", DefaultValue = false)] public bool Sell { get; set; } [Parameter("Pip Step", DefaultValue = 20, MinValue = 1)] public int PipStep { get; set; } [Parameter("First Volume", DefaultValue = 10000, 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 = 100, MinValue = 1)] public int AverageTakeProfit { get; set; } [Parameter("Stop Loss", DefaultValue = 0)] public int StopLoss { get; set; } private double CurrentSpread { get { return (Symbol.Ask - Symbol.Bid) / Symbol.PipSize; } } private SimpleMovingAverage _SMA_slow; private SimpleMovingAverage _SMA_Fast; protected override void OnStart() { } protected override void OnTick() { _SMA_slow = Indicators.SimpleMovingAverage(Source_SMA, 200); _SMA_Fast = Indicators.SimpleMovingAverage(Source_SMA, 50); if (_SMA_slow.Result.LastValue > _SMA_Fast.Result.LastValue && _SMA_slow.Result.LastValue > Symbol.Bid) { Buy = false; Sell = true; ChartObjects.DrawText("Sell", ("Vender"), StaticPosition.TopLeft, Colors.AliceBlue); } if (_SMA_slow.Result.LastValue < _SMA_Fast.Result.LastValue && _SMA_slow.Result.LastValue < Symbol.Ask) { Buy = true; Sell = false; ChartObjects.DrawText("buy", ("Comprar"), StaticPosition.TopLeft, Colors.AliceBlue); } 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(); } 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) { 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) { 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, long volumeToUse) { var returnResult = 0; if (volumeToUse > 0) { var result = ExecuteMarketOrder(tradeType, Symbol, volumeToUse, Label, StopLoss, 0, 0, "smart_grid"); if (result.IsSuccessful) { Print(tradeType, "Opened at: ", result.Position.EntryPrice, result.Position.StopLoss); 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); } else ChartObjects.RemoveObject("bpoint"); if (CountOfTradesOfType(TradeType.Sell) > 1) { var z = CalculateAveragePositionPrice(TradeType.Sell); ChartObjects.DrawHorizontalLine("spoint", z, Colors.HotPink, 2, LineStyle.Dots); } else ChartObjects.RemoveObject("spoint"); ChartObjects.DrawText("pan", GenerateStatusText(), StaticPosition.TopLeft, Colors.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; long count = 0; foreach (var position in Positions) { if (position.Label == Label && position.SymbolCode == Symbol.Code) { if (position.TradeType == tradeType) { averagePrice += position.EntryPrice * position.Volume; count += position.Volume; } } } 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 long GetMostRecentPositionVolume(TradeType tradeType) { long 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.Volume; 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 long CalculateVolume(TradeType tradeType) { var numberOfPositions = CountNumberOfPositionsOfType(tradeType); var mostRecentVolume = GetMostRecentPositionVolume(tradeType); var calculatedVolume = Symbol.NormalizeVolume(mostRecentVolume * Math.Pow(VolumeExponent, numberOfPositions)); return (calculatedVolume); } private long LimitVolume(long volumeIn) { var symbolVolumeMin = Symbol.VolumeMin; var symbolVolumeMax = Symbol.VolumeMax; var result = volumeIn; if (result < symbolVolumeMin) result = symbolVolumeMin; if (result > symbolVolumeMax) result = symbolVolumeMax; return (result); } } }
[Parameter("Sell", DefaultValue = false)] public bool Sell { get; set; }
Hi.
What wrrong.
Bot now open buy and sell ?!
sell is false ?!
defaultvalue is ignore ?
How fix ?
how put parametrs ?
[Parameter("Maximum open buy position?", Group = "Basic Setup", DefaultValue = 5, MinValue = 0)]
public int MaxOpenBuy { get; set; }
[Parameter("Maximum open Sell position?", Group = "Basic Setup", DefaultValue = 5, MinValue = 0)]
public int MaxOpenSell { get; set; }
1
2
[Parameter("Sell", DefaultValue = false)]
public bool Sell { get; set; }
Hi.
What wrrong.
Bot now open buy and sell ?!
sell is false ?!
defaultvalue is ignore ?
How fix ?
got the answer, the parameter is control buy sell when there are no position.
if we need to control when there are position opened, need to adjust code as below
Old
if (CountOfTradesOfType(TradeType.Buy) > 0)
New
if (CountOfTradesOfType(TradeType.Buy) > 0 && Buy)
Now i have issue with this bot, same as username "9469cd97" post on 2015
i run this bot on VPS and on GBPUSD. start i open buy and sell and then the i have waiting 10 positions on buy so i stop buy by set parameter to only sell. (not buy positions remain, not close them)
anyway system still open buy when pips step is meet condition.
i even try to rerun ctrader and delete instance but issue still persist. so sad.
anyone know how to solve?
Friends,
I feel like I have almost honed in on something worthy. I have figured that USDJPY and CHFJPY are very highly correlated most of the time, so therefor being long USDJPY and short CHFJPY at the same time can quite often yield good results, the swap is also positive overall this way.
The method I am using so far, with positive returns on both days after 2 days, cannot be backtested as it relies on running 2 instances of this bot on the same account at the same time (which also keeps your equity somewhat in balance). This means it has to be used in a demo account, unless one of you smart cookies can figure out a way to cross-test and share the best results. Here are my settings so far, please try to optimise them for better return / lower drawdown and get back to me:
Chart : USDJPY
Timeframe : 15 min
Buy : Yes
Sell : No
Pipstep : 5
Volume Exponent : 1.1
Average TP : 4
First Volume : 2000 (0.20 LOT)
Max Spread : 2
Account Margin : 40000 US DOLLAR
Leverage : 1/500
---AND---
Chart : CHFJPY
Timeframe : 15 min
Buy : No
Sell : Yes
Pipstep : 5
Volume Exponent : 1.1
Average TP : 4
First Volume : 2000 (0.20 LOT)
Max Spread : 2
Account Margin : 40000 US DOLLAR
Leverage : 1/500
Test starts by 14.05.2019 Time:17:00 (UTC+3)
Chart : EURUSD
Timeframe : 3 min
Buy : Yes
Sell : Yes
Pipstep : 8
Volume Exponent : 1.1
Average TP : 4
First Volume : 10.000 (0.10 LOT)
Max Spread : 3
Account Margin : 10.000 US DOLLAR
Leverage : 1/10
Margin Call : %30
Who use in real account or VPS ?
Hi guys, this is probably the most mentioned and most popular cBot on cTrader. I have re-written the code and posted the code on github. Since the comments on this page is very long. I also created a new cBot link on ctrader.com, you guys can post any new comment on the new page.
Very special thanks to SaifBD for posting the very original code on to ctrader.com, that made the version 1 of the code
Special thanks to Candeias for re-writing the decompiled code to more human readable code which made the version 2 of the code.
Below are the improvements for the new code.
1. Code has been cleaned up and shortened to half, from over 400 lines to 200 lines. I added some comments in the code for easier understanding on the cBot;
2. Open buy and open sell Boolean was replaced with maximum open buy and sell number. For example, if you predict future is bullish market, set Maximum open sell position to 0;
3. The long-awaited stop loss was added. However, setting up stop loss is not recommended. If you don't need to enable stop loss, set stop loss to a very large number;
4. Setup parameters were grouped, new feature for cTrader 3.5
5. Added close all trade on stop flag to easy back test and forward test cBot. Currently, cTrader backtester does not show equity with open position when cBot stopped. So, this feature is crucial for accurate back test.
6. cTrader does not handle order take profit well, so, instead of setting a take profit value, this version will check open position on each tick and will execute close order then condition met.
7. I only back tested with this cBot, so, the chart drawing function was not tested. Chart drawing code was the original code from version 2.
Hi guys, this is a very good cbot and if properly managed you will mke good profit in the long run, I use to trade with similer EA on MT4 so it was easy for me to modify it to what I was used to. below is how my modified version works:
If Buy is yes, the bot will buy and then place a BuyLimit for the next posible buy if price goes negative and if TP is hit, the BuyLimit is deleted.
I also introduce hedging system to protect account wip out, but once the heding system is triggard, if the TP is hit, all trades will close at small profit and if SL is hit, all trade will close at reasonable loss but account will not wip out. PM:- patways at rocketmail dot com
there are eight functions listed below
------------------------------------------
int <- cnt_16()
double <- D_TD(-)
double <- U_TD(-)
double <- f-tk(-)
long <- It_8(-)
long <- clt(-)
int <- Grd_Ex(-,-)
long <- n_It(-)
------------------------------------
u have'nt used them any where, what r their purpose?
Hi, Candeias & dfwilkie83
this is a greate bot, i have been using and testing it for more than 6 months now, but is is still show several errors based on the last once you have published
i have some greate ideas that if implemented on this bot it will convert it to a an excllent highly profitable bot but this needs a C# skill which i don't have, are you into discussing this project ?
Here it goes, debugged and updated
//
//+------------------------------------------------------------------+
//| 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)
{
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)
{
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);
}
}
}
@dfwilkie83 Did you manage to fix that one error on the end of the code?
Anyone using this successfully for a while? If so, how do you prevent the massive drawdowns?
It trades great for a little while after backtesting and then activating it, but once it hits the trend the wrong way it wipes out the account.
If anyone has a way to prevent this, please share or let me know I can pay for a modification to the bot.
[saka.nakhonsri]
change volume exponent to suit increase in volume you want ( in your case it looks like 2 )
i have found 1.1 to be steady , even a little change to 1.2 can have a dramatic change at certain time frames
@zilva or bruno.inaciocandeias@gmail.com
how to make Smart Grid cBot to be able to open (in case of volume traded) new positions every 1k ... 1k ...2k....4k....8k...16k....32k....64k........xxk when cBot is increasing sell or buy side?
Thank you
Great work. I was wondering if there was any way to eliminate the losses. bot makes great profit but also losses great profit too. can more parameters be set to use with optimization?
Ok got it down to 1 Error , can someone please advise.
using System;
using System.Linq;
using cAlgo.API;
using cAlgo.API.Internals;
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();
}
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)
{
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)
{
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, long 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);
}
else
ChartObjects.RemoveObject("bpoint");
if (CountOfTradesOfType(TradeType.Sell) > 1)
{
var z = CalculateAveragePositionPrice(TradeType.Sell);
ChartObjects.DrawHorizontalLine("spoint", z, Colors.HotPink, 2, LineStyle.Dots);
}
else
ChartObjects.RemoveObject("spoint");
ChartObjects.DrawText("pan", GenerateStatusText(), StaticPosition.TopLeft, Colors.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;
long count = 0;
foreach (var position in Positions)
{
if (position.Label == Label && position.SymbolCode == Symbol.Code)
{
if (position.TradeType == tradeType)
{
averagePrice += position.EntryPrice * position.Volume;
count += position.Volume;
}
}
}
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 long 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);
}
}
}
Can someone please fix this Bot , not working this week after update .
I will pay you or teach you how to use settings or both
I have made alot of money off this one bot !
email me
damosiege@gmail.com
Hey zedodia, do you know how to fix these errors ?
, im not that great at programming but know how make the settings work for most currencies
Great little bot you made there. Since the update theres a few errors on build. Also I find that it always buys and sell regardless of selection.
Error CS0618: 'cAlgo.API.Position.Volume' is obsolete: 'Use VolumeInUnits instead'
Error CS0618: 'cAlgo.API.Internals.Symbol.NormalizeVolume(double, cAlgo.API.RoundingMode)' is obsolete: 'Use NormalizeVolumeInUnits instead'
Error CS0618: 'cAlgo.API.Internals.Symbol.VolumeMin' is obsolete: 'Use VolumeInUnitsMin instead'
Error CS0618: 'cAlgo.API.Internals.Symbol.VolumeMax' is obsolete: 'Use VolumeInUnitsMax instead'
How to convert to mt4? I traded both platforms.
@[amantalpur007@gmail.com] here you go:
//+------------------------------------------------------------------+
//| 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;
using cAlgo.API.Indicators;
using cAlgo.API.Internals;
using cAlgo.Indicators;
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("Source SMA_AO")]
public DataSeries Source_SMA { get; set; }
[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; }
[Parameter("Stop Loss", DefaultValue = 10)]
public int StopLoss { get; set; }
private double CurrentSpread
{
get { return (Symbol.Ask - Symbol.Bid) / Symbol.PipSize; }
}
private SimpleMovingAverage _SMA_slow;
private SimpleMovingAverage _SMA_Fast;
protected override void OnStart()
{
}
protected override void OnTick()
{
_SMA_slow = Indicators.SimpleMovingAverage(Source_SMA, 200);
_SMA_Fast = Indicators.SimpleMovingAverage(Source_SMA, 50);
if (_SMA_slow.Result.LastValue > _SMA_Fast.Result.LastValue && _SMA_slow.Result.LastValue > Symbol.Bid)
{
Buy = false;
Sell = true;
ChartObjects.DrawText("Sell", ("Vender"), StaticPosition.TopLeft, Colors.AliceBlue);
}
if (_SMA_slow.Result.LastValue < _SMA_Fast.Result.LastValue && _SMA_slow.Result.LastValue < Symbol.Ask)
{
Buy = true;
Sell = false;
ChartObjects.DrawText("buy", ("Comprar"), StaticPosition.TopLeft, Colors.AliceBlue);
}
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();
}
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)
{
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)
{
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, long volumeToUse)
{
var returnResult = 0;
if (volumeToUse > 0)
{
var result = ExecuteMarketOrder(tradeType, Symbol, volumeToUse, Label, StopLoss, 0, 0, "smart_grid");
if (result.IsSuccessful)
{
Print(tradeType, "Opened at: ", result.Position.EntryPrice, result.Position.StopLoss);
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);
}
else
ChartObjects.RemoveObject("bpoint");
if (CountOfTradesOfType(TradeType.Sell) > 1)
{
var z = CalculateAveragePositionPrice(TradeType.Sell);
ChartObjects.DrawHorizontalLine("spoint", z, Colors.HotPink, 2, LineStyle.Dots);
}
else
ChartObjects.RemoveObject("spoint");
ChartObjects.DrawText("pan", GenerateStatusText(), StaticPosition.TopLeft, Colors.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;
long count = 0;
foreach (var position in Positions)
{
if (position.Label == Label && position.SymbolCode == Symbol.Code)
{
if (position.TradeType == tradeType)
{
averagePrice += position.EntryPrice * position.Volume;
count += position.Volume;
}
}
}
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 long GetMostRecentPositionVolume(TradeType tradeType)
{
long 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.Volume;
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 long CalculateVolume(TradeType tradeType)
{
var numberOfPositions = CountNumberOfPositionsOfType(tradeType);
var mostRecentVolume = GetMostRecentPositionVolume(tradeType);
var calculatedVolume = Symbol.NormalizeVolume(mostRecentVolume * Math.Pow(VolumeExponent, numberOfPositions));
return (calculatedVolume);
}
private long LimitVolume(long volumeIn)
{
var symbolVolumeMin = Symbol.VolumeMin;
var symbolVolumeMax = Symbol.VolumeMax;
var result = volumeIn;
if (result < symbolVolumeMin)
result = symbolVolumeMin;
if (result > symbolVolumeMax)
result = symbolVolumeMax;
return (result);
}
}
}
Added this to define direction of trades using SMA crossing:
protected override void OnTick()
{
_SMA_slow = Indicators.SimpleMovingAverage(Source_SMA, 200);
_SMA_Fast = Indicators.SimpleMovingAverage(Source_SMA, 50);
if (_SMA_slow.Result.LastValue > _SMA_Fast.Result.LastValue && _SMA_slow.Result.LastValue > Symbol.Bid)
{
Buy = false;
Sell = true;
// ChartObjects.DrawText("Sell", ("Vender"), StaticPosition.TopLeft, Colors.AliceBlue);
}
if (_SMA_slow.Result.LastValue < _SMA_Fast.Result.LastValue && _SMA_slow.Result.LastValue < Symbol.Ask)
{
Buy = true;
Sell = false;
// ChartObjects.DrawText("buy", ("Comprar"), StaticPosition.TopLeft, Colors.AliceBlue);
}
I am trying the code with the 15min timeframe. But the things with this bot is that it has to know when to stop adding more positions to a losing position. The idea is very good. But it has to know when the 15min trendline is broken and it has to be able to close the losing positions and start again opening positions in the new trend.
Every week there are some pairs that a gaining or extending very much pips. And if the bot is trading that pair you can have very huge losses. So: if you are able to create a way to make it a little bit smarter it is a very good code.
it would be much better if somebody paste the whole coding with stop loss included in it. i've tried to add stop loss code but it is not working for me, unfortunately. please paste the whole script of coding. thanks
i hope, someone will do it. :)
hey, somebody please tell me how to set STOP LOSS in this bot. so that i dont have to set it manually every time there's new trade. i'm not good in coding. pls help me out. thanks
To the one who created this bot, thanks a lot! I am currently making real money using this bot. I only trade in one direction, either buy or sell.... I am currently trading 1k volume only with ~ 40 USD per day. Sure to make you smile every morning! :)
Now, I am starting to build up my equity to be able to trade higher volumes.
This cbot has a fundemental flaw in it. it will keep adding losing positions in a trending market even with a stop loss it does not change how the bot works it will contine to do the same thing so the stop loss has no effect on capital preservation. That is why it has crazy drawdowns which will lead to a margin call. we all know that the markets will go into a hard trend at some point. this bot will clean out your account in those times.
Dont try to use stop loss on this grid bot. That strategy then totally loses half of its sense and purpose, just use your account size as your stop loss, decide on some basic capital which can hold reasonable amounts of pips for your parameter set and then withdraw any extra money from your account regularly.
This bot looks incredibly dangerous if you don't know what you're doing (but then I guess all of forex is if you don't know.) It's sad to see someone lost their account here.
Looks like a martingale style keep increasing risk until you win, but if you keep risking until you run out of equity, you are doomed.
Hi. Could someone create an updated version of this, with the sugestions people shared above? Probably not everyone knows how to encode or update by itself. Or eventually someone could teach? Thanks.
Hi ctid264552,
Would you please send me some back test results. I am interested in this CBOT or could i talk to you via Skype or email.
Thanks Ross.
Hi sailBD,
I was just wondering if i could talk to you privately on skype.
Thanks Ross.
@Piratetunes
Thank you for your SL code from March 17. This bot is great, even for newbie like me....
i do back test with BRENT . it working good . make profit every month 30% - 660%. test date 1-30 of month..
account blown with default setting , please dont use
hello what are the modified settings you using ?
hello everyone , i would like to know what pair is good for this bot .. also can anyone tell me money mangment for this bot for 1k account thanks
From Aug 3 2016 to Oct 13 2016
1K -> 2.7k profit - not bad for SELL only no stop loss at GBPJPY.
https://gyazo.com/795c6c2de38a3830a8dbee46adefb13f
Hi I been trying this bot with my live acc. Started with $10000 since march 2016. My net profit atm is around $1800. Not bad. Worth drawdown is around $800-900. Currently the drawdown is $80. I am not saying this will work for sure with everyone. Trading on EURUSD 1D.
or C# in order to test it with Protrader, thanks
i want to this this bot at Metatrader, can anybody port it to MQL4?
Kind of love this robot bus as users before have said it have its flaws.
Ive also added a stoploss but without any success.
Have anyone tried to add maximum number of trades in any direction?
And this pip step feature... will it close a position after like xx candles in a 15 minutes chart? or how does that work?
You can help me? I would like to change it yet. I would like to submit a maximum number of trades for direction (for example 10 to buy and 10 per sell) and maybe every time the logarithm by a new buy / sell signal this to run (perhaps with a larger volume) and it is closed to further loss.
I do not know if this will work better I would try and hear other opinions or ideas.
Thanks very much to everyone
PS. is it possible to change the volumes in lots instead of money so as to try this algorithm also about indexes?
I give first a quick option. I added a Stop Loss. http://gigapeta.com/dl/6562936a98dfba
This is a great robot, but there are drawbacks. When he loses a strong trend. I am a C # programmer and try to modify it (add StopLoss and trend indicators stochastic, MACD Crossover). What do you think, if my attempt to be successful, I have the right to put it here without the approval of the author?
I must say. it seems there has been a system fault causing this loss. is there any way of getting some of the money back?
thanks
hello.
I've been using smartgrid for some months now, and today 12000 dollars were lost, due to an immense decline as to the value of eur/zar.. I've been having stoploss all the time but today something did not quite go the way it should have. I am in a horrible shcock, and is right now trying to make some sence of this. Is there any way you could help me minimise the risk of this occuring once more?
I've been frightened from continuing and I would like som support as how to procede.
many thanks.
Bot does not work correctly. I have set parameters to sell only, but bot still opens buy positions :(
Hi [SaifBD] . Great cbot, I agree with others though about the equity drawdown. I'm having trouble adding the stoploss to the code, calgo keeps giving back error readings. Is there a possibility you or somebody else could post the whole Smart Grid code with the stop loss included? It would be much appriciated.
Many thanks.
Good day, is this Cbot valid or still works on Ctrader version 1.35.64939?
Hello everybody,
while I tested this cBot I get better result using Onbar method of optimalization... But cAlgo gave me an attention - something like this robot is programmed for OnTick. So my question is it possible to change parameters to OnBar?And which must be changed? Thanks
@zilva
bitte schick' mir eine email an
info@sicherfair.de
Danke
Kurt
@Piratetunes
Thank you for your suggestions from March 17. The bot works really good, even on a small EUR 1000 account.
Put this at the top
[Parameter("Stop Loss", DefaultValue = 10)]
public int StopLoss { get; set; }
Copy below section and paste whole section, or simply add StopLoss after Label.
private int OrderSend(TradeType tradeType, long volumeToUse)
{
var returnResult = 0;
if (volumeToUse > 0)
{
var result = ExecuteMarketOrder(tradeType, Symbol, volumeToUse, Label, StopLoss, 0, 0, "smart_grid");
if (result.IsSuccessful)
{
Print(tradeType, "Opened at: ", result.Position.EntryPrice, result.Position.StopLoss);
returnResult = 1;
}
else
Print(tradeType, "Openning Error: ", result.Error);
}
else
Print("Volume calculation error: Calculated Volume is: ", volumeToUse);
return returnResult;
}
I can't seem to get any working stop loss. I am not a coder but have researched every possible solution with no results. I love this code and would like to use it with minimum drawdown. If anyone is willing to help I would greatly appreciate it.
Regards
Hello,
i think, this is a very good cbot, but can someone help me to add a "Stop Loss"
i'm not a programmer, so i have no idea to do this (i've tried it - but with no results)
thx a lot !
Hi Guys,
does someone has good results with this bot ? if yes on wich symbol and with which paramaters values ?
i you could publish results of backtesting or myfxbook perf it would be nice !
Thanks a lot and have good trades ;)
Hey man this thing is working great, but some equity drawdowns are just too hard!
I had a maximum equity drawdown of 110% so i would be in a complete loss. What can we do against that?
From the best I can tell this codebase is based on some type of mt4 ea that was decompiled which made it difficult to read and follow. I was looking to do some modifications to the code so before I started I decided to clean things up so I could see what was going on. I am posting the results (hopefully) the logic should be the same as the original but a bit easier to read. Note, backtest this bot as it like most grid based bots can get into a catastrophic equity drain if the underlying starts to trend hard.
//+------------------------------------------------------------------+
//| 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();
}
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)
{
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)
{
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, long 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);
}
else
ChartObjects.RemoveObject("bpoint");
if (CountOfTradesOfType(TradeType.Sell) > 1)
{
var z = CalculateAveragePositionPrice(TradeType.Sell);
ChartObjects.DrawHorizontalLine("spoint", z, Colors.HotPink, 2, LineStyle.Dots);
}
else
ChartObjects.RemoveObject("spoint");
ChartObjects.DrawText("pan", GenerateStatusText(), StaticPosition.TopLeft, Colors.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;
long count = 0;
foreach (var position in Positions)
{
if (position.Label == Label && position.SymbolCode == Symbol.Code)
{
if (position.TradeType == tradeType)
{
averagePrice += position.EntryPrice*position.Volume;
count += position.Volume;
}
}
}
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 long GetMostRecentPositionVolume(TradeType tradeType)
{
long 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.Volume;
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 long CalculateVolume(TradeType tradeType)
{
var numberOfPositions = CountNumberOfPositionsOfType(tradeType);
var mostRecentVolume = GetMostRecentPositionVolume(tradeType);
var calculatedVolume = Symbol.NormalizeVolume(mostRecentVolume*Math.Pow(VolumeExponent, numberOfPositions));
return (calculatedVolume);
}
private long LimitVolume(long volumeIn)
{
var symbolVolumeMin = Symbol.VolumeMin;
var symbolVolumeMax = Symbol.VolumeMax;
var result = volumeIn;
if (result < symbolVolumeMin)
result = symbolVolumeMin;
if (result > symbolVolumeMax)
result = symbolVolumeMax;
return (result);
}
}
}
@SaifBD
This algo is amazing but the only problem is, is that with a smaller starting capital, the amount of trades for a certain lot size will decrease dramatically compared to the same lot size with a higher starting capital. Could you please fix this some how, as I don't know anything about coding. Or if you could reply and I'll give you my e-mail address so we can talk.
Thankyou
would it make sense to have "max. trades"? on my demo runnung smart grid ihave now 17 positions!
could i copy a line with max trades from another bot and put it into smart grid?
That's great ..
do you have a one for the metatrader ?
@ Relax...
it is possible, just code what you want to do in onBar() instead of onTick().
@8051361
In easy Words.... It calculate all positions in one Direction to compensate Profit and Loss, then just added Take Profit.
@ Piratetunes, @ Conno123
Just ad a Stoploss in ExecuteMarketOrder (TradeType, Symbol, Volume, Label, STOPLOSS, TakeProfit, Marketrange, Comment)
Beste Grüße (Greetz)
zilva
Has anyone got a working stop loss feature?
Could they possibly share the code?
I have built with a stoploss code, but it does not actually set the stop loss.
Thanks
@[SaifBD]
One word Awesome!
I am new to cBots and dont have a programmers brain :(. Wondering if you could explain the Take Profit calculation I am not able to figure out the logic.
If its not too much trouble.
Thanks.
OK, thank you for your point of view. I will double test that on demo acc.
Just one more question...Is it possibile to change code to check conditions by set timeframe instead of checking by each tick? I mean that when I am using 1m timeframe I want code to be checked after each 1m candle. If cBot conditions are met at the beginning of 1m candle (pipstep distance and maxspread) ,then he should open next position, if not then wait till next 1m candle and check again...Is such change possible?
Thank you once more,
RelaX
Yes, in the description is written one trade per bar.
For me is it still not necessary to open only one trade per bar, so i don't search for the Code to do that.
By the way, nice to help you ;)
great JOB!
@ Zilva
Thank you very much for ammendments in code. After adding new parameter and changes in Method n_lt(TradeType ca_8) cBOT is working like I wanted.
There is one more case to figure out in cBOT. I notice the same what @Cannon123 wrote that cBOT is executing more then 1 trade per bar. In cBOT description there is written that cBOT contains code which should limit drawdown by adding only one trade per bar. It is not working correctly. I also check that with oryginal code and the same happen.
Even if I am using 1m timeframe and PipStep =10 and there is big move on the market during market data release cBOT is opening more then 1 position in 1 minute bar if the price movement is exceeding PipStep paramether during 1m candle drawing. I would like to make changes which will limit that risk and create new order at the beggining of next 1m bar instead of opening somewhere in the middle of bar. So if the price movement is higher then PipStep paramether during 1m candle drawing cBOT should open position at the begining of next bar. I think that cBOT conditions should be validate on bar instead of on tick but when newly created position is added, TP modifications should be created immediately on tick.
Is that possibile? Can you assist with such changes as well?
Cheers,
RelaX
@ Conno123.
Okay, just found the Error.
replace this:
long ld_4 = Symbol.NormalizeVolume(gi_c + VolumeStep);
with this:
long ld_4 = Symbol.NormalizeVolume(gi_c + (VolumeStep * ic_g));
greetz
zilva
Is there anyone that could code a multiplier to the pip step parameter? I would appreciate this with cash thankyou.
@ Relax
Set New Parameter:
[Parameter("Volume Step", DefaultValue = 1000, MinValue = 1000, Step = 1000)]
public int VolumeStep { get; set; }
And replace the Method n_lt(TradeType ca_8) with This:
private long n_lt(TradeType ca_8)
{
int ic_g = Grd_Ex(ca_8, ca_8);
long gi_c = lt_8(ca_8);
long ld_4 = Symbol.NormalizeVolume(gi_c + VolumeStep);
return (ld_4);
}
I did not tested this, but seems to be work.
hello SafiiBD,
is it possible to build a filter in this cBot only long -only short and long and short.
plus a stop los possibility.
Nice Robot. Works in backtesting pretty good but i really miss a stopp loss. SafiBD can you please add this feature to the cBot?
Does anyone know how to set new parameter in that cBot to be able to open (in case of volume traded) new positions every 1k or 2k or 3k...when cBot is increasing sell or buy side? Let's say that I would like to start from 1k and then have next position 2k and 3k and 4k and so on, when I set step volume to 1k. So newly created position is always 1k volume higher then previous one. Next example - when I set first volume and step volume to 2k I would like to have 2k then 4k, 6k, 8k, 10k and so on. Next buy or sell position should be always 2k volume higher then previous one in that example. All other functionality of cBot should stay as it is now. No other changes. Can anyone help with that?
Could you add a step exponent multiplier so as to increase the pip step with each position that is added?
@[SaifBD]
Hello,
[SaifBD] is it possible to add Step Volume paramether to your cBot? So if I set First Volume to 1000 and Step Volume to 1000 then cBot should open 1k then 2k then 3k then 4k then 5k and so on...if I set First Volume to 2000 and Step Volume to 2000 then cBot should open 2k then 4k then 6k then 8k and so on...is that possibile? I want cBot to add value seted in Step Volume paramether when opening next position instead of using Volume Exponent paramether. Is that possibile?
For now there is only Volume Exponent paramether which multiplies previous volume when I set it more then 1.0
This looks good but it does not seem to have a stop loss by default. I've added:
private double pipSize;
private double stopLoss = 3.6;
private double sL;
and then added this to the order method:
if (TrdTp == TradeType.Sell)
{
sL = Symbol.Ask + stopLoss * pipSize;
}
else if (TrdTp == TradeType.Buy)
{
sL = Symbol.Bid - stopLoss * pipSize;
}
int cd_8 = 0;
if (iVol > 0)
{
TradeResult result = ExecuteMarketOrder(TrdTp, Symbol, iVol, Label, sL, 0, 0, "smart_grid");
Is this ok or is there a better way to do this?
@SaifBD
Make it more clear. I open two "AUDCAD" pair cBots, one with only "Buy" option and another with only "Sell" option then start both cBots, in the middle of time, I stopped one with "Sell" option and let another keep running, from this moment on, cBot should only open Buy position is that correct? somehow it still open Sell position and that really confuse me.
@SaifBD
Sorry to bother you, but I have an issue need your help.
I using AUDCAD pair to run optimization and parameters shows both "Buy-Yes" and "Sell-Yes", then I run it in Live account with only "Buy-Yes" setting and cAlgo still open Sell position, is that normal?
Thanks a lot.
@zilva try this.
[Parameter("Max Volume", DefaultValue = 10000000, Step = 1000)]
public int MaxVolume { get; set; }
if (ic_8 > MaxVolume)
ic_8 = MaxVolume;
@SaifBD This is IMO the Max tradable Volume of a Symbol.
I mean to set myself the max i want to risk.
P.S. spike.bhv is my old ID.
[SaifBD] is a pleasure i have a great strategie that worth the soot programming it are you interested my mail
burnigonhell@gmail.com
@spike.bhv
I added that in my cBot. see
long dc_i = Symbol.VolumeMax;
if (ic_8 > dc_i)
ic_8 = dc_i;
I send you a friend request.
The Method is to validate the tradeble Volume (min, max, and steps) of this symbol.
f.e. if exist (i don't know that) a maximum tradevolume for a symbol, this Method set the maximum if you want a higher volume.
Hope you understand what i mean. My English is not very good...
in the method private long fer(long ic_9, int bk_4) he never actuallyuses this variavle what is funny long gd_i = Symbol.VolumeStep;
i dont find you my facebook is: https://www.facebook.com/omar.hernandez.167189
on Facebook ;)
search for Mi Be in Bremerhaven / Germany
hi spike do u use any social network like facebook or linkedIn Id like to talk to u
One Word: Amazing ;)
I've added some Features:
Volume Maximum (if Volume Exponent >1)
PipStep Maximum (if Volume Maximum ist reached, alternative set Buy / Sell flag = false)
Stop Loss ( not importend, but cTrader will note when Stoploss not set)
Advanced Stopp Loss. I set TP a lttle bit higher then AverageTP. When current price reached TP-1 Pip (for Example) New StopLoss will be set TP - 3 (for Example), wich is = Average TP. The TP will increased by TrailingStep. So if the Curent Price will grow up, the (Trailing) Stop Loss will grow up too.
Sorry for my bad english, I'm German ;)
this is by far the best bot i ever seen
where did you learn all of this?
Part, can I add a start to this grid once the RSI reaches a given value? for example this one:
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 SampleRSIcBot : Robot
{
[Parameter("Quantity (Lots)", Group = "Volume", DefaultValue = 1, MinValue = 0.01, Step = 0.01)]
public double Quantity { get; set; }
[Parameter("Source", Group = "RSI")]
public DataSeries Source { get; set; }
[Parameter("Periods", Group = "RSI", DefaultValue = 14)]
public int Periods { get; set; }
[Parameter("Lower RSI Level", Group = "RSI", DefaultValue = 30, MinValue = 0, MaxValue = 50)]
public int LRL { get; set; }
[Parameter("Upper RSI Level", Group = "RSI", DefaultValue = 70, MinValue = 50, MaxValue = 100)]
public int URL { get; set; }
[Parameter("Take Profit in pips", Group = "TP SL", DefaultValue = 100)]
public int TP { get; set; }
[Parameter("Stop Loss in pips", Group = "TP SL", DefaultValue = 100)]
public int SL { get; set; }
private RelativeStrengthIndex rsi;
protected override void OnStart()
{
rsi = Indicators.RelativeStrengthIndex(Source, Periods);
}
protected override void OnTick()
{
if (rsi.Result.LastValue < LRL)
{
Close(TradeType.Sell);
Open(TradeType.Buy);
}
else if (rsi.Result.LastValue > URL)
{
Close(TradeType.Buy);
Open(TradeType.Sell);
}
}
private void Close(TradeType tradeType)
{
foreach (var position in Positions.FindAll("SampleRSI", SymbolName, tradeType))
ClosePosition(position);
}
private void Open(TradeType tradeType)
{
var position = Positions.Find("SampleRSI", SymbolName, tradeType);
var volumeInUnits = Symbol.QuantityToVolumeInUnits(Quantity);
if (position == null)
ExecuteMarketOrder(tradeType, SymbolName, volumeInUnits, "SampleRSI", SL, TP);
}
}
}