Description
DISCLAIMER DISCLAIMER DISCLAIMER!!! While we have been having some very good success with this Forex trading robot for cAlgo platform (a cTrader robotic trading platform) you must USE IT AT YOUR OWN RISK. It is not perfect!
For the last few months we have been developing Forex trading strategies and so far, we are getting some pretty interesting results. In some cases, obscenely great profits! NOTE NOTE NOTE!!! We are not trying to sell you anything here, in-fact, you can download this Forex trading robot for free at the bottom of this article and try it for yourself. Our GOAL is to collaborate with the Forex community and other Forex programmers to work on optimizing and improving this automated Forex trading robot. In fact, that is the very reason we are sharing this bot with the community. It's not perfect, and we want to improve it. So if you have any suggestions, for how to improve this Forex bot, please leave a comment on our Facebook page, The Dot Millionaire, and like our page if you want to be a part of our community. We are making millionaires. That is our goal. Both in the Forex market and in other online marketing and ecommerce ventures. So tune in to receive and share tips.
That all being said, this little Forex bot ran for 5 months in back-testing and returned a happy 1006% profit. So, we are calling this Forex bot, the Rasmussen Martingale Bot and this is version 4.0. You can download it at the bottom of this page, but first... some instructions:
Here's how it works.
1. Automatic Lot Management
The bot will automatically increase your initial starting lot amount based on the current balance of your account. So if you start with 1 initial lot, and earn 50% on your account, the bot will now be trading at 1.5 lots. It will scale up and down depending on how much your account has earned, but it will never drop below the starting amount.
Theoretically: this will have a compounding effect over time (and potentially a very quick compounding effect). We have seen it happen in back-testing and it can be VERY powerful. The option to toggle this feature on or off exists.
2. Martingale Multiplier
We seem to have found that a multiplier around 2.5 works the best, but play around with it. This variable will determine the multiplication of all martingale trades, so lets assume that you lose 1 lot, and have martingale set to 2, your next trade will be for 2 lots and the trade after that will be for 4 lots, and then 8 lots and then 16 (until the bot wins a trade and recovers any lost revenue).
That is the theory behind the martingale effect, it's a loss protection scheme with the one major drawback: that over time, it will eventually fail and crash out the entire account. That's a pretty big drawback, but on the other hand, if you can run a martingale bot for 5 months before that happens, you could return some very serious profits, especially with the automatic lot management feature.
3. Shutdown Amount and Trading Cycle
You will have the option to reset all bot parameters every cycle, the cycle can be an hour or it could be a year, it's entirely up to you. If during the cycle period the bot experiences a draw down on your account balance which exceeds the shutdown amount, then in order to filter out any potentially unusual days in trading, the bot can shut down all trading until the next cycle period begins. This feature can also be useful for back-testing a days performance at a time without being influenced by previous days.
And quite a few more features, I'll continue this documentation shortly. In the meantime, play around and let me know what improvements you think might help.
I have had some interesting results in backtesting. Not much live testing yet though. Attaching some screenshots.
using System;
using System.Linq;
using System.Collections.Generic;
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 RasmussenMartingalev4 : Robot
{
[Parameter("- - - Money Management Variables - - -", DefaultValue = "")]
public string DoNothing01 { get; set; }
[Parameter("Initial Quantity (Lots)", DefaultValue = 1, MinValue = 0.01, Step = 0.01)]
public double InitialQuantity { get; set; }
[Parameter("Automatic Lots Management", DefaultValue = true)]
public bool AutomaticMoneyManagementFlag { get; set; }
[Parameter("Martingale Multiplier", DefaultValue = 2.0)]
public double Multiplier { get; set; }
[Parameter("Stop Loss", DefaultValue = 100)]
public double StopLoss { get; set; }
[Parameter("Trailing Stop Loss", DefaultValue = 20.0)]
public double TrailingStop { get; set; }
[Parameter("Take Profit", DefaultValue = 100)]
public double TakeProfit { get; set; }
[Parameter("Martingale Overrides Take Profit?", DefaultValue = true)]
public bool TPOverridenFlag { get; set; }
[Parameter("Shut Down Amount (in $)", DefaultValue = 500)]
public double ShutDown { get; set; }
[Parameter("Max Martingale Drawdown (in %)", DefaultValue = 20)]
public double MartingaleDrawdown { get; set; }
[Parameter("- - - Price Action Variables - - -", DefaultValue = "")]
public string DoNothing02 { get; set; }
[Parameter("Number of Candles", DefaultValue = 5, MinValue = 1)]
public int CandlesNumber { get; set; }
[Parameter("Follow the Trend", DefaultValue = true)]
public bool FollowTrend { get; set; }
[Parameter("Ignore candle direction", DefaultValue = false)]
public bool IgnoreDirectionFlag { get; set; }
[Parameter("Use candle difference?", DefaultValue = false)]
public bool UseCandleDifference { get; set; }
[Parameter("Candle Difference (in %)", DefaultValue = 50)]
public double DifferenceBetweenCandles { get; set; }
[Parameter("Filter tiny candles?", DefaultValue = true)]
public bool FilterTinyCandles { get; set; }
[Parameter("Minimum Last Candle Size (in Pips)", DefaultValue = 3)]
public double MinCandleSize { get; set; }
[Parameter("- - - Time Sensitive Variables - - -", DefaultValue = "")]
public string DoNothing03 { get; set; }
[Parameter("Minutes between trades", DefaultValue = 0)]
public int MinutesBetweenTrades { get; set; }
[Parameter("Drop boring trades", DefaultValue = true)]
public bool DropTrades { get; set; }
[Parameter("Boring Trade Duration (Minutes)", DefaultValue = 30, MinValue = 1)]
public int BoringDuration { get; set; }
[Parameter("Martingale effect on boring trades?", DefaultValue = false)]
public bool MartingaleBoringTradesFlag { get; set; }
[Parameter("Cycle Period (in hours)", DefaultValue = 24, MinValue = 1)]
public int Cycle { get; set; }
[Parameter("Martingale Overrides Cycle Reset?", DefaultValue = true)]
public bool OverrideCycle { get; set; }
[Parameter("Friday Shutdown", DefaultValue = true)]
public bool FridayShutdownFlag { get; set; }
[Parameter("Friday Shutdown Time", DefaultValue = 21)]
public int EndOfWeekHour { get; set; }
private double BarArrayAverage;
private double StaticVolumeMultiplier = 1;
private double VolumeMultiplier = 1;
private double MaxProfit = 0;
private double CycleProfit = 0;
private double InitialStopLoss;
private double InitialTakeProfit;
private double InitialEquity;
private double MaxEquity;
private double Drawdown;
private double MaxDrawdown;
private double LastCandleSize;
private Queue<double> BarArray = new Queue<double>();
private bool TakeProfitFlag = true;
private bool TrailingStopFlag = false;
private bool ShuttedDownFlag = false;
private bool CycleOverridenFlag = false;
private bool FirstPositionFlag = true;
private DateTime InitialTime;
private DateTime CycleEndTime;
private DateTime TimeForNewPosition;
private DateTime BoringTradeTimer;
private TimeSpan EndOfWeek;
private Position OpenPosition;
protected override void OnStart()
{
EndOfWeek = TimeSpan.FromHours(EndOfWeekHour) - TimeSpan.FromMinutes(1);
InitialEquity = Account.Equity;
InitialStopLoss = StopLoss;
InitialTakeProfit = TakeProfit;
InitializeCycle();
for (int i = 1; i <= CandlesNumber; i++)
{
BarArray.Enqueue(GetBarHeight(i));
}
ResetDrawdown();
}
protected override void OnBar()
{
UpdateBars();
// Closes positions at the end of the week
if (Server.Time.DayOfWeek == DayOfWeek.Friday && Server.Time.TimeOfDay >= EndOfWeek && FridayShutdownFlag == true)
{
if (OpenPosition != null)
{
CloseOpenPosition();
ResetTPFlags();
}
}
// Normal trade logic during the week.
else
{
if (ShuttedDownFlag == false && Server.Time >= TimeForNewPosition)
{
if (IgnoreDirectionFlag == true)
{
//...for a bullish trend.
if (LastCandleSize > 0 && OpenPosition == null)
{
//Checking the trend or countertrend variable.
var _TradeType = FollowTrend ? TradeType.Buy : TradeType.Sell;
FilterAndExecuteTrades(_TradeType);
}
//...for a bearish trend.
else if (LastCandleSize < 0 && OpenPosition == null)
{
//Checking the trend or countertrend variable.
var _TradeType = FollowTrend ? TradeType.Sell : TradeType.Buy;
FilterAndExecuteTrades(_TradeType);
}
}
else
{
//Checking if entry condition has been met...
var OverZero = BarArray.Where(x => x > 0);
var SubZero = BarArray.Where(x => x < 0);
//...for a bullish trend.
if (OverZero.Count() == CandlesNumber && OpenPosition == null)
{
//Checking the trend or countertrend variable.
var _TradeType = FollowTrend ? TradeType.Buy : TradeType.Sell;
FilterAndExecuteTrades(_TradeType);
}
//...for a bearish trend.
if (SubZero.Count() == CandlesNumber && OpenPosition == null)
{
//Checking the trend or countertrend variable.
var _TradeType = FollowTrend ? TradeType.Sell : TradeType.Buy;
FilterAndExecuteTrades(_TradeType);
}
}
}
}
}
protected override void OnTick()
{
// Closes positions at the end of the week
if (Server.Time.DayOfWeek == DayOfWeek.Friday && Server.Time.TimeOfDay >= EndOfWeek && FridayShutdownFlag == true)
{
if (OpenPosition != null)
{
Print("Closing all positions");
CloseOpenPosition();
ResetTPFlags();
}
}
// Normal trade logic during the week.
else
{
//Checking the drawdown of the acccount.
if (Account.Equity > MaxEquity)
ResetDrawdown();
else
{
var CurrentDrawdown = MaxEquity - Account.Equity;
Drawdown = CurrentDrawdown > Drawdown ? CurrentDrawdown : Drawdown;
if (Drawdown > MaxDrawdown)
{
CloseOpenPosition();
ResetTPFlags();
ResetMartingaleVariables();
ResetDrawdown();
}
}
//Checking if the cycle has ended;
if (Server.Time >= CycleEndTime && CycleOverridenFlag == false)
{
CloseOpenPosition();
ResetTPFlags();
ResetMartingaleVariables();
InitializeCycle();
}
// Closing trade logic.
if (ShuttedDownFlag == false)
{
//Checks if the TS is active.
if (TrailingStopFlag == true)
{
UpdateMaxProfit();
UpdateStopLoss();
}
//Checks if there's an open position.
if (OpenPosition != null)
{
// Activates TS when TP is reached.
if (OpenPosition.NetProfit >= TakeProfit && TakeProfitFlag == true)
{
ActivateTrailingStop();
}
//Checking the shut down properties.
if (CycleProfit + OpenPosition.NetProfit <= -ShutDown)
{
ShuttedDownFlag = true;
CloseOpenPosition();
Print("Shutted down until next cycle.");
}
// Stop Loss logic.
else if (OpenPosition.NetProfit <= -StopLoss)
{
CloseOpenPosition();
// If the TP was never reached, the position volume is multiplied.
if (TakeProfitFlag == true)
ApplyMartingaleEffect();
else
ResetMartingaleVariables();
ResetTPFlags();
}
//Closing boring positions.
else if (FirstPositionFlag == true && DropTrades == true && Server.Time >= BoringTradeTimer)
{
var LoserTrade = OpenPosition.NetProfit < 0;
CloseOpenPosition();
if (MartingaleBoringTradesFlag == true && LoserTrade == true)
ApplyMartingaleEffect();
ResetTPFlags();
}
}
}
}
}
private void ActivateTrailingStop()
{
TakeProfitFlag = false;
TrailingStopFlag = true;
MaxProfit = OpenPosition.NetProfit;
UpdateStopLoss();
}
private DateTime AddWorkDays(DateTime originalDate, int workDays)
{
DateTime tmpDate = originalDate;
while (workDays > 0)
{
tmpDate = tmpDate.AddDays(1);
if (tmpDate.DayOfWeek < DayOfWeek.Saturday && tmpDate.DayOfWeek > DayOfWeek.Sunday)
workDays--;
}
return tmpDate;
}
private DateTime AddWorkHours(DateTime originalDate, int workHours)
{
DateTime tmpDate = originalDate;
while (workHours > 0)
{
tmpDate = tmpDate.AddHours(1);
if (tmpDate.DayOfWeek < DayOfWeek.Saturday && tmpDate.DayOfWeek > DayOfWeek.Sunday)
workHours--;
}
return tmpDate;
}
private DateTime AddWorkMinutes(DateTime originalDate, int workMinutes)
{
DateTime tmpDate = originalDate;
while (workMinutes > 0)
{
tmpDate = tmpDate.AddMinutes(1);
if (tmpDate.DayOfWeek < DayOfWeek.Saturday && tmpDate.DayOfWeek > DayOfWeek.Sunday)
workMinutes--;
}
return tmpDate;
}
private void ApplyMartingaleEffect()
{
// This volume multiplier will be affected by the automatic money management.
VolumeMultiplier = Multiplier * StaticVolumeMultiplier;
StaticVolumeMultiplier = Multiplier * StaticVolumeMultiplier;
StopLoss = InitialStopLoss * VolumeMultiplier;
TakeProfit = TPOverridenFlag ? InitialStopLoss * VolumeMultiplier : InitialTakeProfit * VolumeMultiplier;
FirstPositionFlag = false;
if (OverrideCycle == true)
CycleOverridenFlag = true;
if (AutomaticMoneyManagementFlag == true)
AutomateMoneyManagement();
}
private void AutomateMoneyManagement()
{
var MMMultiplier = Account.Equity > InitialEquity ? Account.Equity / InitialEquity : 1;
VolumeMultiplier = VolumeMultiplier * MMMultiplier;
StopLoss = StopLoss * MMMultiplier;
TakeProfit = TakeProfit * MMMultiplier;
}
private void CloseOpenPosition()
{
if (OpenPosition != null)
{
var Result = ClosePosition(OpenPosition);
if (Result.IsSuccessful)
{
OpenPosition = null;
CycleProfit += Result.Position.NetProfit;
TimeForNewPosition = AddWorkMinutes(Server.Time, MinutesBetweenTrades);
}
}
}
private void ExecuteOrder(TradeType _TradeType)
{
var Result = ExecuteMarketOrder(_TradeType, Symbol, Symbol.NormalizeVolume(Symbol.QuantityToVolume(InitialQuantity * VolumeMultiplier)));
if (Result.IsSuccessful)
{
OpenPosition = Result.Position;
if (FirstPositionFlag == true)
{
BoringTradeTimer = AddWorkMinutes(Server.Time, BoringDuration);
}
}
}
private void FilterAndExecuteTrades(TradeType _TradeType)
{
//Order execution when using difference between candles.
if (UseCandleDifference == true)
{
var Difference = BarArray.ToList()[CandlesNumber - 1] * 100 / BarArrayAverage - 100;
if (Difference >= DifferenceBetweenCandles)
FilterTinyCandlesAndExecute(_TradeType);
}
else
FilterTinyCandlesAndExecute(_TradeType);
}
private void FilterTinyCandlesAndExecute(TradeType _TradeType)
{
// Order execution when avoiding tiny candles.
if (FilterTinyCandles == true)
{
if (Math.Abs(BarArray.ToList()[CandlesNumber - 1]) > MinCandleSize * Symbol.PipSize)
ExecuteOrder(_TradeType);
}
else
ExecuteOrder(_TradeType);
}
private double GetBarHeight(int index)
{
double Close = MarketSeries.Close.Last(1);
double Open = MarketSeries.Open.Last(1);
LastCandleSize = Close - Open;
if (IgnoreDirectionFlag)
return Math.Abs(LastCandleSize);
else
return LastCandleSize;
}
private void InitializeCycle()
{
InitialTime = Server.Time;
CycleEndTime = AddWorkHours(InitialTime, Cycle);
ShuttedDownFlag = false;
CycleProfit = 0;
Print("A new cycle began. Ends on {0}", CycleEndTime);
}
private void ResetDrawdown()
{
MaxEquity = Account.Equity;
Drawdown = 0;
MaxDrawdown = MaxEquity * MartingaleDrawdown / 100;
}
private void ResetTPFlags()
{
TakeProfitFlag = true;
TrailingStopFlag = false;
}
private void ResetMartingaleVariables()
{
VolumeMultiplier = 1;
StaticVolumeMultiplier = 1;
StopLoss = InitialStopLoss;
TakeProfit = InitialTakeProfit;
CycleOverridenFlag = false;
FirstPositionFlag = true;
if (AutomaticMoneyManagementFlag == true)
AutomateMoneyManagement();
}
private void UpdateBars()
{
BarArray.Dequeue();
BarArrayAverage = BarArray.Average();
BarArray.Enqueue(GetBarHeight(1));
}
private void UpdateMaxProfit()
{
MaxProfit = OpenPosition.NetProfit > MaxProfit ? OpenPosition.NetProfit : MaxProfit;
}
private void UpdateStopLoss()
{
StopLoss = -MaxProfit + TakeProfit * TrailingStop / 100;
}
}
}
romesvonwolf
Joined on 01.06.2017
- Distribution: Free
- Language: C#
- Trading platform: cTrader Automate
- File name: Rasmussen Martingale v4.algo
- Rating: 0
- Installs: 4623
- Modified: 13/10/2021 09:55
Comments
Hi.
Please help me provide code in this cBot to change SL/TP values to system current ATR, each time a new trade is generated.
Thanks.
Hello romesvonwolf,
i still downloaded your cbot. Now i have some questions regarding the stting of the cbot.
Possible to get in contact...?
regards
Stefan
Hi.
When I start the robot nothing happens.
Does anyone know why this is?
Thanks
George.
I do not trust backtests, or even optimising, but it can be a good place to start. Having now done lots of promising back tests, as well as some live forward tests, it is making good profits. If the trend continues I shall risk some real money soon'ish. I am trying it out on lots of pairs, with AudUsd and UsdJpy being favourites for me. Using a setup derived from Optimising the past 90 days I then allowed live Demo trading and each made sensible decisions and good profits. BUT it is still far too early to know if this is all a fluke, or is repeatable.
I think readers ought to know that the 'Martingale' aspect is far from being the usual wild erratic suicide ride that most are, but instead it can be used in a managed limited way, or not at all. Please do not be put off by the Martingale name, in this case it is just a shorthand for a logical response to some errant trades.
'Rasmussen' seems to have a decent trade selection mechanism, however only time and live trading will tell. It would be good to hear from other users or interested parties as the author suggested. I shall be making a few suggestions once I am ready, as well as making saved Parameter Setups available to anybody who wants to share them. Quid Pro Quo, as they say ;)
Fascinating work, clearly lots of effort went into this, thanks for sharing it. Just started running tests but seems to have real potential, but all trading needs great care of course. Fingers Crossed ;)
if you like this bot and make improvements, please share with the community!
is there anyone who can correct this for me. I would like the number of martingale trades not to go on indefinitely.in this bot
i tried it with : if (StaticVolumeMultiplier.Length <= MaxTrades) ResetTPFlags(); ResetMartingaleVariables(); ResetDrawdown();
private void ApplyMartingaleEffect()
{
// This volume multiplier will be affected by the automatic money management.
VolumeMultiplier = Multiplier + StaticVolumeMultiplier;
StaticVolumeMultiplier += Multiplier ;
if (StaticVolumeMultiplier.Length <= MaxTrades)
ResetTPFlags();
ResetMartingaleVariables();
ResetDrawdown();
StopLoss = InitialStopLoss + VolumeMultiplier;
TakeProfit = TPOverridenFlag ? InitialStopLoss + VolumeMultiplier : InitialTakeProfit + VolumeMultiplier;
FirstPositionFlag = false;
if (OverrideCycle == true)
CycleOverridenFlag = true;
if (AutomaticMoneyManagementFlag == true)
AutomateMoneyManagement();
}