Description
The Mechanic Bot uses the Candlestick Tendency indicator as a decision driver for entering trades. The basic idea is to trade higher order timeframe with current local timeframe. It trades a single position at a time and has mechanisms for trailing stops and basic money management. Here's the list of parameters and their descriptions:
HighOrderTimeFrame - which higher timeframe to use for deciding on trend direction, default value is h1 (it's ok to leave it like that). This parameter gets forwarded to the Candlestick Tendency indicator. This is recommended to be at least 4x local timeframe. If you use minutes for the main local timeframe, then use minutes over hours for a higher timeframe, or hours over days, days over months etc...
Volume - the trading amount, default is 10000, set this to whatever is satisfied by backtesting.
EnableStopLoss - the name says it all, default is true to use stoploss mechanism, it's highly recommended to leave it as is (do not turn stoploss off unless you know what you're doing).
StopLoss - the stoploss value, in pips, default is 20 (if enabled).
EnableBreakEven - use breakeven mechanism or not, default is false (do not move to break even), other breakeven settings only have effect when this setting is true.
BreakEvenPips - the amount of pips to set break even stoploss to, default is 10.
BreakEvenGain - the minimal amount of profitable pips that triggers a move to break even, default is 20.
EnableTrailingStop - use trailing stop mechanism or not, default is false, other trailing stop settings only have effect when this setting is true.
TrailingStop - the amount of trailing pips, default is 10 (if enabled).
TrailingStart - the minimal amount of profitable pips to start trailing (if enabled).
EnableTakeProfit - use the takeprofit mechanism or not, default is true, highly recommended to leave it on.
TakeProfit - the amount of take profit pips, default is 30, set this to whatever is satisfied by backtesting.
EnterOnSyncSignalOnly - only trade when both local and global trends change direction on the same bar simultaneously, default is true. This setting increases the win/lose ratio, but can reduce the total amount of trades. That is, when this setting is set to true, the bot will make less trades and less mistakes, but this will probably take more time.
ExitOnOppositeSignal - exit a position on opposite signal, default is false. This can generate a lot of noise and false signals, so it is recommended to leave it off.
Installation:
1. Download and install the Candlestick Tendency indicator.
2. Download and install this bot.
3. Set a reference to Candlestick Tendency in reference manager before building the bot (3rd screenshot)
4. Build the bot.
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 Mechanic : Robot {
// general params
[Parameter ()]
public TimeFrame HighOrderTimeFrame { get; set; }
[Parameter (DefaultValue = 10000, Step = 1000, MinValue = 1000)]
public int Volume { get; set; }
[Parameter (DefaultValue = true)]
public bool EnableStopLoss { get; set; }
[Parameter (DefaultValue = 20, MinValue = 1, Step = 1)]
public double StopLoss { get; set; }
[Parameter (DefaultValue = false)]
public bool EnableBreakEven { get; set; }
[Parameter (DefaultValue = 10, MinValue = 0, Step = 1)]
public double BreakEvenPips { get; set; }
[Parameter (DefaultValue = 20, MinValue = 0, Step = 1)]
public double BreakEvenGain { get; set; }
[Parameter (DefaultValue = false)]
public bool EnableTrailingStop { get; set; }
[Parameter (DefaultValue = 10, MinValue = 1, Step = 1)]
public double TrailingStop { get; set; }
[Parameter (DefaultValue = 10, MinValue = 1, Step = 1)]
public double TrailingStart { get; set; }
[Parameter (DefaultValue = true)]
public bool EnableTakeProfit { get; set; }
[Parameter (DefaultValue = 30, MinValue = 0)]
public int TakeProfit { get; set; }
[Parameter (DefaultValue = true)]
public bool EnterOnSyncSignalOnly { get; set; }
[Parameter (DefaultValue = false)]
public bool ExitOnOppositeSignal { get; set; }
private string label;
private const int indexOffset = 0;
private int index;
private CandlestickTendency tendency;
public bool globalTendencyWasLong;
public bool globalTendencyWasShort;
public bool localTendencyWasLong;
public bool localTendencyWasShort;
public Position currentPosition { get { return Positions.Find (label); }}
public bool inPosition { get { return currentPosition != null; }}
public bool inShortPosition { get { return currentPosition != null && currentPosition.TradeType == TradeType.Sell; }}
public bool inLongPosition { get { return currentPosition != null && currentPosition.TradeType == TradeType.Buy; }}
public bool globalTendencyIsLong { get { return tendency.HighOrderLine[index] > 0; }}
public bool localTendencyIsLong { get { return tendency.Line[index] > 0; }}
public bool globalTendencyIsShort { get { return tendency.HighOrderLine[index] < 0; }}
public bool localTendencyIsShort { get { return tendency.Line[index] < 0; }}
public bool longSignal { get { return localTendencyIsLong && globalTendencyIsLong; }}
public bool shortSignal { get { return localTendencyIsShort && globalTendencyIsShort; }}
public bool closeSignal { get { return inPosition ? ((currentPosition.TradeType == TradeType.Sell) ? longSignal : shortSignal) : false; }}
protected override void OnStart () {
label = "Mechanic " + Symbol.Code + " " + TimeFrame.ToString () + " / " + HighOrderTimeFrame.ToString ();
tendency = Indicators.GetIndicator <CandlestickTendency> (HighOrderTimeFrame);
index = MarketSeries.Close.Count - 1;
}
protected void UpdateTrailingStops () {
if (!EnableTrailingStop)
return;
var positions = Positions.FindAll (label);
if (positions == null)
return;
foreach (var position in positions) {
if (position.Pips >= TrailingStart) {
if (position.TradeType == TradeType.Buy) {
var newStopLoss = Symbol.Bid - TrailingStop * Symbol.PipSize;
if (position.StopLoss < newStopLoss)
ModifyPosition (position, newStopLoss, null);
} else if (position.TradeType == TradeType.Sell) {
var newStopLoss = Symbol.Ask + TrailingStop * Symbol.PipSize;
if (position.StopLoss > newStopLoss)
ModifyPosition (position, newStopLoss, null);
}
}
}
}
protected void MoveToBreakEven () {
if (!EnableBreakEven)
return;
var positions = Positions.FindAll (label);
if (positions == null)
return;
foreach (var position in positions) {
if (position.Pips >= BreakEvenPips) {
if (position.TradeType == TradeType.Buy) {
var newStopLoss = Symbol.Bid - BreakEvenGain * Symbol.PipSize;
if (position.StopLoss < newStopLoss)
ModifyPosition (position, newStopLoss, null);
} else if (position.TradeType == TradeType.Sell) {
var newStopLoss = Symbol.Ask + BreakEvenGain * Symbol.PipSize;
if (position.StopLoss > newStopLoss)
ModifyPosition (position, newStopLoss, null);
}
}
}
}
protected TradeResult EnterInPosition (TradeType direction) {
if (!EnableStopLoss && EnableTakeProfit)
return ExecuteMarketOrder (direction, Symbol, Volume, label, null, TakeProfit);
if (!EnableStopLoss && !EnableTakeProfit)
return ExecuteMarketOrder (direction, Symbol, Volume, label, null, null);
if (EnableStopLoss && !EnableTakeProfit)
return ExecuteMarketOrder (direction, Symbol, Volume, label, StopLoss, null);
return ExecuteMarketOrder (direction, Symbol, Volume, label, StopLoss, TakeProfit);
}
protected override void OnTick () {
index = MarketSeries.Close.Count - 1;
UpdateTrailingStops ();
MoveToBreakEven ();
}
protected override void OnBar () {
index = MarketSeries.Close.Count - 2;
if (ExitOnOppositeSignal && closeSignal)
ClosePosition (currentPosition);
if (!inPosition) {
if (EnterOnSyncSignalOnly) {
if (localTendencyWasShort && globalTendencyWasShort && localTendencyIsLong && globalTendencyIsLong) {
EnterInPosition (TradeType.Buy);
} else if (localTendencyWasLong && globalTendencyWasLong && localTendencyIsShort && globalTendencyIsShort) {
EnterInPosition (TradeType.Sell);
}
} else {
if (shortSignal) {
EnterInPosition (TradeType.Sell);
} else if (longSignal) {
EnterInPosition (TradeType.Buy);
}
}
}
localTendencyWasLong = localTendencyIsLong;
localTendencyWasShort = localTendencyIsShort;
globalTendencyWasLong = globalTendencyIsLong;
globalTendencyWasShort = globalTendencyIsShort;
}
protected override void OnStop () {
}
}
}
igorkroitor
Joined on 03.01.2015
- Distribution: Free
- Language: C#
- Trading platform: cTrader Automate
- File name: Mechanic.algo
- Rating: 2.5
- Installs: 6991
- Modified: 13/10/2021 09:54
Comments
Hello Igor!
1) Can you please implement some kind of equity protection code to stop the operation of the cBot if the equity falls below a certain bottom limit?
2) And, also, it would be great if you could provide a vice versa algorithm which would automatically stop the cBot if the equity reaches a certain amount?
3) Why the back testing results show (in "trade statistics) in the end an increased balance, but a reduced equity? It seems strange to me... (e.g., Ending Balance is 1061, but Ending Equity is 824 - ???)
I have make a backtest with good result :
params :
[ChartParameters]
Symbol = EURUSD
Timeframe = m1[cBotParameters]
HighOrderTimeFrame = Hour
Volume = 10000
EnableStopLoss = True
StopLoss = 69
EnableBreakEven = False
BreakEvenPips = 10
BreakEvenGain = 20
EnableTrailingStop = False
TrailingStop = 10
TrailingStart = 10
EnableTakeProfit = True
TakeProfit = 5
EnterOnSyncSignalOnly = False
ExitOnOppositeSignal = True
The result between 1/05/2015 and 06/07/2015 is
+ 12465 euros (2571 trades and 2039 winnings trades)
The tendancy Candle is a good direction to search a profitable signal
Thanks to igorkroitor for this good bot.
Hello there
In code there is no difference between
UpdateTrailingStop
and
MoveToBreakEven
http://www.algochart.com/report/jhgh6
10m 1h higher time frame - 4 years backtest on GBP/USD . Live trading has replicated the back test in recent weeks
Hi Igorkroitor, thanks for this bot.
When running this bot live the take profit does not seem to work - is there a bug that needs to be fixed? The build is successful. The enabletakeprofit function is set to yes but the trades do not set a take profit level.
Regards
Alex
Thx igorkroitor.
Can you give recommendations what settings to use?
Backtest (Tickdata) 26.01.2014... 05.02.2015, EU, m2
http://www.algochart.com/report/5iif1
Really nice chart -- but wrong direction! ;-)
Can anyone advise how we would go about closing open trades in a direction, if the trend changes direction?
Setting a stop loss can be too restrictive so was trying to use the following but get errors:
ClosePosition(TradeType.Sell); or ClosePosition(shortSignal);
Error CS1502: The best overloaded method match for 'cAlgo.API.Robot.ClosePosition(cAlgo.API.Position)' has some invalid arguments
Error CS1503: Argument 1: cannot convert from 'cAlgo.API.TradeType' to 'cAlgo.API.Position'
Im getting stuck with the code trying to simply close any open trades as per below.....
protected override void OnBar()
{
index = Bars.ClosePrices.Count - 2;
if (ExitOnOppositeSignal && closeSignal)
ClosePosition(currentPosition);
//if (!inPosition)
{
if (EnterOnSyncSignalOnly)
{
if (localTendencyWasShort && globalTendencyWasShort && localTendencyIsLong && globalTendencyIsLong)
{
EnterInPosition(TradeType.Buy);
ClosePosition(TradeType.Sell); or ClosePosition(shortSignal);
}
else if (localTendencyWasLong && globalTendencyWasLong && localTendencyIsShort && globalTendencyIsShort)
{
EnterInPosition(TradeType.Sell);
ClosePosition(TradeType.Buy); or ClosePosition(longSignal);
}
}
else
{
if (shortSignal)
{
EnterInPosition(TradeType.Sell);
ClosePosition(TradeType.Buy); or ClosePosition(longSignal);
}
else if (longSignal)
{
EnterInPosition(TradeType.Buy);
ClosePosition(TradeType.Sell); or ClosePosition(shortSignal);
}