Description
Hey-ho!
Let us introduce the cBot with a built-in BB indicator. This cool trading tool will help you to monitor price volatility.
Features
The BB strategy can:
- Check ready-formed bars and current price position. You can select the right time to open a trade.
- Work in 3 modes: Current price and BB line crossing (Current Breakout), Closing of the last bar above/below the line (Close Above/Below), Price and the last crossed bar crossing (Bar Cross).
- Manage positions.
- Calculate all the risks for the entire position.
- Remove the Stop Loss level on the opening price after overcoming a certain distance thanks to the BreakEven option. In this case, your trade won’t be a loss-making one.
Note! You can select the BB line (Top or Bottom) and crossing type for every trade type.
Parameters
We have equipped our EA with more than 14 additional parameters. So, you can configure the cBot according to your needs!
Note! Try the Bollinger Bands strategy on your demo account first before going live.
Other Products
Ichimoku Cloud System:
PSAR Strategy:
ADR Custom Indicator:
Daily H/L Custom Indicator:
Contact Info
Contact us via support@4xdev.com.
Check out our cozy Telegram blog for traders: https://t.me/Forexdev.
Visit our website to find more tools and programming services: https://bit.ly/44BFRG3
Take a look at our YouTube channel: https://www.youtube.com/channel/UChsDb4Q8X2Vl5DJ7H8PzlHQ.
Feel the heavenly pleasure of trading — with 4xDev.
using cAlgo.API;
using cAlgo.API.Indicators;
using System;
namespace cAlgo.Robots
{
[Robot(TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
public class BbTradeSystem : Robot
{
public enum ENUM_TP_TYPE
{
Fixed = 0,
RiskRatio = 1
}
public enum ENUM_RISK_SOURCE
{
Equity = 0,
Balance = 1
}
public enum ENUM_LOT_TYPE
{
Fixed_Lot = 0,
Percent = 1
}
public enum ENUM_CROSS_TYPE
{
Current_Breakout = 0,
//Current breakout
Close_Above_Below = 1,
//Close Above/Below
Bar_Cross = 2
//Bar Cross
}
public enum ENUM_CROSS_LINE
{
Top_Line = 0,
// Top Line
Bottom_Line = 1
// Bottom Line
}
public enum ENUM_CROSS_DIRECTION
{
Above = 0,
// Above
Below = 1
// Below
}
#region Input BB Parameters
[Parameter("BB Source", Group = "BB Parameters")]
public DataSeries BBSeries { get; set; }
[Parameter("BB Period", Group = "BB Parameters", DefaultValue = 20)]
public int BBPeriods { get; set; }
[Parameter("Bands Deviation", Group = "BB Parameters", DefaultValue = 2)]
public double deviation { get; set; }
[Parameter("MA Type", Group = "BB Parameters")]
public MovingAverageType maType { get; set; }
#endregion
#region Input Trade Parameters
[Parameter("Label", Group = "Trade Parameters", DefaultValue = "BB Trade System")]
public string Label { get; set; }
[Parameter("Cross Type", Group = "Trade Parameters", DefaultValue = ENUM_CROSS_TYPE.Current_Breakout)]
public ENUM_CROSS_TYPE crossType { get; set; }
[Parameter("Buy Cross Line", Group = "Trade Parameters", DefaultValue = ENUM_CROSS_LINE.Bottom_Line)]
public ENUM_CROSS_LINE crossLineBuy { get; set; }
[Parameter("Buy Cross Direction", Group = "Trade Parameters", DefaultValue = ENUM_CROSS_DIRECTION.Below)]
public ENUM_CROSS_DIRECTION crossDirectBuy { get; set; }
[Parameter("Sell Cross Line", Group = "Trade Parameters", DefaultValue = ENUM_CROSS_LINE.Top_Line)]
public ENUM_CROSS_LINE crossLineSell { get; set; }
[Parameter("Sell Cross Direction", Group = "Trade Parameters", DefaultValue = ENUM_CROSS_DIRECTION.Above)]
public ENUM_CROSS_DIRECTION crossDirectSell { get; set; }
[Parameter("Take Profit type", Group = "Trade Parameters", DefaultValue = ENUM_TP_TYPE.Fixed)]
public ENUM_TP_TYPE tpType { get; set; }
[Parameter("Stop Loss in pips", Group = "Trade Parameters", DefaultValue = 0)]
public double SL { get; set; }
[Parameter("Take Profit value", Group = "Trade Parameters", DefaultValue = 0)]
public double TP { get; set; }
[Parameter("Close on the opposite signal", Group = "Trade Parameters", DefaultValue = true)]
public bool oppositeClose { get; set; }
[Parameter("Max Orders", Group = "Trade Parameters", DefaultValue = 1)]
public int maxOrders { get; set; }
[Parameter("Use Reverse Trade", Group = "Trade Parameters", DefaultValue = true)]
public bool reverseTrade { get; set; }
#endregion
#region Input Lot Size Parameters
[Parameter("Lot Type", Group = "Lot Size", DefaultValue = ENUM_LOT_TYPE.Fixed_Lot)]
public ENUM_LOT_TYPE lotType { get; set; }
[Parameter("Risk Source", Group = "Lot Size", DefaultValue = ENUM_RISK_SOURCE.Balance)]
public ENUM_RISK_SOURCE riskSource { get; set; }
[Parameter("Risk/Lot Value", Group = "Lot Size", DefaultValue = 0.1)]
public double risk { get; set; }
#endregion
#region Input Break Even Parameters
[Parameter("Use BreakEven", Group = "BreakEven", DefaultValue = false)]
public bool UseBE { get; set; }
[Parameter("BreakEven Start(pips)", Group = "BreakEven", DefaultValue = 10)]
public double BEStart { get; set; }
[Parameter("BreakEven Profit(pips)", Group = "BreakEven", DefaultValue = 0)]
public double BEProfit { get; set; }
#endregion
private BollingerBands BB;
protected override void OnStart()
{
BB = Indicators.BollingerBands(BBSeries, BBPeriods, deviation, maType);
// Put your initialization logic here
}
double bbPrevTop;
double bbPrevBott;
double pricePrev;
DateTime lastTrade;
protected override void OnTick()
{
if (UseBE)
BreakEven();
if (lastTrade != Bars.OpenTimes.Last(0))
{
if (CheckCondition(TradeType.Buy))
{
if (oppositeClose)
CloseOrders(TradeType.Sell);
if(CalculateOrders() < maxOrders)
{
lastTrade = Bars.OpenTimes.Last(0);
OpenOrder(TradeType.Buy);
}
}
if (CheckCondition(TradeType.Sell))
{
if (oppositeClose)
CloseOrders(TradeType.Buy);
if(CalculateOrders() < maxOrders)
{
lastTrade = Bars.OpenTimes.Last(0);
OpenOrder(TradeType.Sell);
}
}
}
bbPrevTop = BB.Top.Last(0);
bbPrevBott = BB.Bottom.Last(0);
pricePrev = Bars.ClosePrices.Last(0);
}
bool CheckOrder(TradeType type)
{
if (Positions.FindAll(Label, Symbol, type) != null)
return false;
return true;
}
int CalculateOrders()
{
return Positions.FindAll(Label, Symbol).Length;
}
void CloseOrders(TradeType type)
{
if (reverseTrade)
type = type == TradeType.Buy ? TradeType.Sell : TradeType.Buy;
foreach (var pos in Positions.FindAll(Label, Symbol, type))
{
ClosePosition(pos);
}
}
void OpenOrder(TradeType type)
{
if (reverseTrade)
type = type == TradeType.Buy ? TradeType.Sell : TradeType.Buy;
double op;
double tp = tpType == ENUM_TP_TYPE.Fixed ? TP : SL * TP;
double sl;
double source = riskSource == ENUM_RISK_SOURCE.Balance ? Account.Balance : Account.Equity;
double volumeInUnits = 0;
if (lotType == ENUM_LOT_TYPE.Fixed_Lot)
volumeInUnits = Symbol.QuantityToVolumeInUnits(risk);
else
volumeInUnits = CalculateVolume(SL, risk, source);
if (volumeInUnits == -1)
return;
ExecuteMarketOrder(type, SymbolName, volumeInUnits, Label, SL, TP);
}
private void BreakEven()
{
if (!UseBE)
return;
foreach (var pos in Positions.FindAll(Label, SymbolName))
{
if (pos.TradeType == TradeType.Buy)
{
if (Symbol.Ask >= pos.EntryPrice + BEStart * Symbol.PipSize && (pos.StopLoss < pos.EntryPrice + BEProfit * Symbol.PipSize || pos.StopLoss == null))
{
ModifyPosition(pos, pos.EntryPrice + BEProfit * Symbol.PipSize, pos.TakeProfit);
}
}
if (pos.TradeType == TradeType.Sell)
{
if (Symbol.Bid <= pos.EntryPrice - BEStart * Symbol.PipSize && (pos.StopLoss > pos.EntryPrice - BEProfit * Symbol.PipSize || pos.StopLoss == null))
{
ModifyPosition(pos, pos.EntryPrice + BEProfit * Symbol.PipSize, pos.TakeProfit);
}
}
}
}
bool CheckCondition(TradeType trade)
{
int shift = crossType == ENUM_CROSS_TYPE.Current_Breakout ? 0 : 1;
double bb;
double bbPrev;
if (trade == TradeType.Buy)
{
if (crossLineBuy == ENUM_CROSS_LINE.Top_Line)
bb = BB.Top.Last(shift);
else
bb = BB.Bottom.Last(shift);
if (crossType == ENUM_CROSS_TYPE.Current_Breakout)
{
if (crossLineBuy == ENUM_CROSS_LINE.Top_Line)
bbPrev = bbPrevTop;
else
bbPrev = bbPrevBott;
if (crossDirectBuy == ENUM_CROSS_DIRECTION.Above)
{
if (Bars.ClosePrices.Last(0) < bb && pricePrev > bbPrev)
return true;
else
return false;
}
if (crossDirectBuy == ENUM_CROSS_DIRECTION.Below)
{
if (Bars.ClosePrices.Last(0) > bb && pricePrev < bbPrev)
return true;
else
return false;
}
}
if (crossType == ENUM_CROSS_TYPE.Close_Above_Below)
{
if (crossDirectBuy == ENUM_CROSS_DIRECTION.Above)
{
if (Bars.ClosePrices.Last(1) > bb)
return true;
else
return false;
}
if (crossDirectBuy == ENUM_CROSS_DIRECTION.Below)
{
if (Bars.ClosePrices.Last(1) < bb)
return true;
else
return false;
}
}
if (crossType == ENUM_CROSS_TYPE.Bar_Cross)
{
if (Bars.LowPrices.Last(1) < bb && Bars.HighPrices.Last(1) > bb)
return true;
else
return false;
}
}
if (trade == TradeType.Sell)
{
if (crossLineSell == ENUM_CROSS_LINE.Top_Line)
bb = BB.Top.Last(shift);
else
bb = BB.Bottom.Last(shift);
if (crossType == ENUM_CROSS_TYPE.Current_Breakout)
{
if (crossLineSell == ENUM_CROSS_LINE.Top_Line)
bbPrev = bbPrevTop;
else
bbPrev = bbPrevBott;
if (crossDirectSell == ENUM_CROSS_DIRECTION.Above)
{
if (Bars.ClosePrices.Last(0) < bb && pricePrev > bbPrev)
return true;
else
return false;
}
if (crossDirectSell == ENUM_CROSS_DIRECTION.Below)
{
if (Bars.ClosePrices.Last(0) > bb && pricePrev < bbPrev)
return true;
else
return false;
}
}
if (crossType == ENUM_CROSS_TYPE.Close_Above_Below)
{
if (crossDirectSell == ENUM_CROSS_DIRECTION.Above)
{
if (Bars.ClosePrices.Last(1) > bb)
return true;
else
return false;
}
if (crossDirectSell == ENUM_CROSS_DIRECTION.Below)
{
if (Bars.ClosePrices.Last(1) < bb)
return true;
else
return false;
}
}
if (crossType == ENUM_CROSS_TYPE.Bar_Cross)
{
if (Bars.LowPrices.Last(1) < bb && Bars.HighPrices.Last(1) > bb)
return true;
else
return false;
}
}
return false;
}
private double CalculateVolume(double stopLossPips, double riskSize, double source)
{
// source = Account.Balance or Account.Equity
double riskPerTrade = source * riskSize / 100;
double totalPips = stopLossPips;
double _volume;
double exactVolume = riskPerTrade / (Symbol.PipValue * totalPips);
if (exactVolume >= Symbol.VolumeInUnitsMin)
{
_volume = Symbol.NormalizeVolumeInUnits(exactVolume);
}
else
{
_volume = -1;
Print("Not enough Equity to place minimum trade, exactVolume " + exactVolume + " is not >= Symbol.VolumeInUnitsMin " + Symbol.VolumeInUnitsMin);
}
return _volume;
}
protected override void OnStop()
{
// Put your deinitialization logic here
}
}
}
4xDev
Joined on 11.12.2019
- Distribution: Free
- Language: C#
- Trading platform: cTrader Automate
- File name: BB_Trade_System.algo
- Rating: 3.33
- Installs: 2489
- Modified: 05/12/2022 12:29
Comments
Thanks for the bot, from the tests it seems very valid.
Using the fpmarkets broker is giving me some warnings:
13/10/2023 13:54:16.565 | → Request to amend position PID2192082 (SL: 158.580) is REJECTED with error "New SL for BUY position should be <= current BID price. current BID: 157.508, SL: 158.58;"
13/10/2023 12:30:02.635 | → Request to amend position PID2169355 is REJECTED with error "Nothing to amend."
In the config the Stop Loss is set to 0
Hi,
trank you for your cbot.
Please, can you tell me where can i find a manual of your Bollinger bands Tranding Strategy cbot explaining the different parameters how they affect the opening of the position?
Thnak you again
@TheMC, we found the problem. The parameter does not work if the maximum number of orders is 1.
We have uploaded the fixed version of the tool.
@TheMC Let us check this problem. We will solve this problem asap.
If you want to create a custom tool, please contact us via support@4xdev.com. Or check our website 4xdev(dot)com.
Hi,
congratulations for the excellent work.
However, it seems to me that the bot does not close positions at the opposite signal.
This doesn't work, position never closes out