Description
This robot is a fork of Robot_Forex. It is hosted on Github and gives good results. If you want to have the last evolutions of the bot, take it here
It manages a stop loss, a money management , a tralling stop and dynamic grid to her positions.
For the parameters to use go to Github
A video a.bout this bot is on youtube
#region Licence
//The MIT License (MIT)
//Copyright (c) 2014 abdallah HACID, https://www.facebook.com/ab.hacid
//Permission is hereby granted, free of charge, to any person obtaining a copy of this software
//and associated documentation files (the "Software"), to deal in the Software without restriction,
//including without limitation the rights to use, copy, modify, merge, publish, distribute,
//sublicense, and/or sell copies of the Software, and to permit persons to whom the Software
//is furnished to do so, subject to the following conditions:
//The above copyright notice and this permission notice shall be included in all copies or
//substantial portions of the Software.
//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
//BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
//NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
//DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
//OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
// Project Hosting for Open Source Software on Github : https://github.com/abhacid/Robot_Forex
#endregion
#region Description
//
// Le projet et sa description se trouvent sur Github à l'adresse https://github.com/abhacid/Martingale_Forex
//
// Ce projet permet d'écrire un robot de trading basé sur un exemple Robot_Forex initial écrit par
// imWald sur le dépôt de code source CTDN.
//
// Pour résumer c'est une martingale avec stop loss et money management.
#endregion
using System;
using System.Collections.Generic;
using cAlgo.API;
using cAlgo.API.Internals;
using cAlgo.Lib;
namespace cAlgo.Robots
{
[Robot("Martingale Forex", AccessRights = AccessRights.None)]
public class Martingale_Forex : Robot
{
#region Parameters
[Parameter("Money Management (%)", DefaultValue = 1.6, MinValue = 0)]
public double MoneyManagement { get; set; }
[Parameter("Take Profit", DefaultValue = 5, MinValue = 5)]
public double TakeProfit { get; set; }
[Parameter("Stop Loss Factor", DefaultValue = 5.5, MinValue = 0.1)]
public double StopLossFactor { get; set; }
[Parameter("Martingale", DefaultValue = 0.5, MinValue = 0)]
public double MartingaleCoeff { get; set; }
[Parameter("Max Orders", DefaultValue = 2, MinValue = 2)]
public int MaxOrders { get; set; }
#endregion
private bool isRobotStopped;
private string botName;
// le label permet de s'y retrouver parmis toutes les instances possibles.
private string instanceLabel;
private double stopLoss;
private double firstLot;
private StaticPosition corner_position;
private string BotVersion = "1.3.2.0";
private bool DEBUG;
protected override void OnStart()
{
DEBUG = true;
botName = ToString();
instanceLabel = botName + "-" + BotVersion + "-" + Symbol.Code + "-" + TimeFrame.ToString();
stopLoss = TakeProfit * StopLossFactor;
Positions.Opened += OnPositionOpened;
int corner = 1;
switch (corner)
{
case 1:
corner_position = StaticPosition.TopLeft;
break;
case 2:
corner_position = StaticPosition.TopRight;
break;
case 3:
corner_position = StaticPosition.BottomLeft;
break;
case 4:
corner_position = StaticPosition.BottomRight;
break;
}
if (!DEBUG)
ChartObjects.DrawText("BotVersion", botName + " Version : " + BotVersion, corner_position);
Print("The current symbol has PipSize of: {0}", Symbol.PipSize);
Print("The current symbol has PipValue of: {0}", Symbol.PipValue);
Print("The current symbol has TickSize: {0}", Symbol.TickSize);
Print("The current symbol has TickSValue: {0}", Symbol.TickValue);
}
protected override void OnTick()
{
if (Trade.IsExecuting)
return;
Position[] positions = GetPositions();
if (positions.Length > 0 && isRobotStopped)
return;
else
isRobotStopped = false;
if (positions.Length == 0)
{
// Calcule le volume en fonction du money management pour un risque maximum et un stop loss donné.
// Ne tient pas compte des risques sur d'autres positions ouvertes du compte de trading utilisé
double maxVolume = this.moneyManagement(MoneyManagement, stopLoss);
firstLot = maxVolume / (MaxOrders + (MartingaleCoeff * MaxOrders * (MaxOrders - 1)) / 2.0);
if (firstLot <= 0)
throw new System.ArgumentException(String.Format("the 'first lot' : {0} parameter must be positive and not null", firstLot));
else
SendFirstOrder(firstLot);
}
else
ControlSeries();
}
protected override void OnError(Error CodeOfError)
{
if (CodeOfError.Code == ErrorCode.NoMoney)
{
isRobotStopped = true;
Print("ERROR!!! No money for order open, robot is stopped!");
}
else if (CodeOfError.Code == ErrorCode.BadVolume)
{
isRobotStopped = true;
Print("ERROR!!! Bad volume for order open, robot is stopped!");
}
}
private void OnPositionOpened(PositionOpenedEventArgs args)
{
double? stopLossPrice = null;
double? takeProfitPrice = null;
switch (GetPositionsSide())
{
case 0:
double averageBuyPrice = GetAveragePrice(TradeType.Buy);
takeProfitPrice = averageBuyPrice + TakeProfit * Symbol.PipSize;
stopLossPrice = averageBuyPrice - stopLoss * Symbol.PipSize;
break;
case 1:
double averageSellPrice = GetAveragePrice(TradeType.Sell);
takeProfitPrice = averageSellPrice - TakeProfit * Symbol.PipSize;
stopLossPrice = averageSellPrice + stopLoss * Symbol.PipSize;
break;
}
if (stopLossPrice.HasValue || takeProfitPrice.HasValue)
{
Position[] positions = GetPositions();
foreach (Position position in positions)
{
if (stopLossPrice != position.StopLoss || takeProfitPrice != position.TakeProfit)
ModifyPosition(position, stopLossPrice, takeProfitPrice);
}
}
}
private void SendFirstOrder(double OrderVolume)
{
switch (GetSignal())
{
case 0:
executeOrder(TradeType.Buy, OrderVolume);
break;
case 1:
executeOrder(TradeType.Sell, OrderVolume);
break;
}
}
private void ControlSeries()
{
Position[] positions = GetPositions();
if (positions.Length < MaxOrders)
{
long volume = Symbol.NormalizeVolume(firstLot * (1 + MartingaleCoeff * positions.Length), RoundingMode.ToNearest);
int countOfBars = (int)(25.0 / positions.Length);
int pipstep = GetDynamicPipstep(countOfBars, MaxOrders - 1);
int positionSide = GetPositionsSide();
switch (positionSide)
{
case 0:
double lastBuyPrice = GetLastPrice(TradeType.Buy);
if (!DEBUG)
ChartObjects.DrawHorizontalLine("gridBuyLine", lastBuyPrice - pipstep * Symbol.PipSize, Colors.Green, 2);
if (Symbol.Ask < lastBuyPrice - pipstep * Symbol.PipSize)
executeOrder(TradeType.Buy, volume);
break;
case 1:
double lastSellPrice = GetLastPrice(TradeType.Sell);
if (!DEBUG)
ChartObjects.DrawHorizontalLine("gridSellLine", lastSellPrice + pipstep * Symbol.PipSize, Colors.Red, 2);
if (Symbol.Bid > lastSellPrice + pipstep * Symbol.PipSize)
executeOrder(TradeType.Sell, volume);
break;
}
}
if (!DEBUG)
ChartObjects.DrawText("MaxDrawdown", "MaxDrawdown: " + Math.Round(GetMaxDrawdown(), 2) + " Percent", corner_position);
}
// You can modify the condition of entry here.
private int GetSignal()
{
int Result = -1;
int LastBarIndex = MarketSeries.Close.Count - 2;
int PrevBarIndex = LastBarIndex - 1;
// two up candles for a buy signal.
if (MarketSeries.Close[LastBarIndex] > MarketSeries.Open[LastBarIndex])
if (MarketSeries.Close[PrevBarIndex] > MarketSeries.Open[PrevBarIndex])
Result = 0;
// two down candles for a sell signal.
if (MarketSeries.Close[LastBarIndex] < MarketSeries.Open[LastBarIndex])
if (MarketSeries.Close[PrevBarIndex] < MarketSeries.Open[PrevBarIndex])
Result = 1;
return Result;
}
private TradeResult executeOrder(TradeType tradeType, double volume)
{
//Print("normalized volume : {0}", Symbol.NormalizeVolume(volume, RoundingMode.ToNearest));
return ExecuteMarketOrder(tradeType, Symbol, Symbol.NormalizeVolume(volume, RoundingMode.ToNearest), instanceLabel);
}
private Position[] GetPositions()
{
return Positions.FindAll(instanceLabel, Symbol);
}
private double GetAveragePrice(TradeType TypeOfTrade)
{
double Result = Symbol.Bid;
double AveragePrice = 0;
long count = 0;
foreach (Position position in GetPositions())
{
if (position.TradeType == TypeOfTrade)
{
AveragePrice += position.EntryPrice * position.Volume;
count += position.Volume;
}
}
if (AveragePrice > 0 && count > 0)
Result = AveragePrice / count;
return Result;
}
private int GetPositionsSide()
{
int Result = -1;
int BuySide = 0, SellSide = 0;
Position[] positions = GetPositions();
foreach (Position position in positions)
{
if (position.TradeType == TradeType.Buy)
BuySide++;
if (position.TradeType == TradeType.Sell)
SellSide++;
}
if (BuySide == positions.Length)
Result = 0;
if (SellSide == positions.Length)
Result = 1;
return Result;
}
private int GetDynamicPipstep(int CountOfBars, int division)
{
int Result;
double HighestPrice = 0, LowestPrice = 0;
int StartBar = MarketSeries.Close.Count - 2 - CountOfBars;
int EndBar = MarketSeries.Close.Count - 2;
for (int i = StartBar; i < EndBar; i++)
{
if (HighestPrice == 0 && LowestPrice == 0)
{
HighestPrice = MarketSeries.High[i];
LowestPrice = MarketSeries.Low[i];
continue;
}
if (MarketSeries.High[i] > HighestPrice)
HighestPrice = MarketSeries.High[i];
if (MarketSeries.Low[i] < LowestPrice)
LowestPrice = MarketSeries.Low[i];
}
Result = (int)((HighestPrice - LowestPrice) / Symbol.PipSize / division);
return Result;
}
private double savedMaxBalance;
private List<double> drawdown = new List<double>();
private double GetMaxDrawdown()
{
savedMaxBalance = Math.Max(savedMaxBalance, Account.Balance);
drawdown.Add((savedMaxBalance - Account.Balance) / savedMaxBalance * 100);
drawdown.Sort();
double maxDrawdown = drawdown[drawdown.Count - 1];
return maxDrawdown;
}
private double GetLastPrice(TradeType tradeType)
{
double LastPrice = 0;
foreach (Position position in GetPositions())
{
if (tradeType == TradeType.Buy)
if (position.TradeType == tradeType)
{
if (LastPrice == 0)
{
LastPrice = position.EntryPrice;
continue;
}
if (position.EntryPrice < LastPrice)
LastPrice = position.EntryPrice;
}
if (tradeType == TradeType.Sell)
if (position.TradeType == tradeType)
{
if (LastPrice == 0)
{
LastPrice = position.EntryPrice;
continue;
}
if (position.EntryPrice > LastPrice)
LastPrice = position.EntryPrice;
}
}
return LastPrice;
}
}
}
aysos75
Joined on 28.09.2013
- Distribution: Free
- Language: C#
- Trading platform: cTrader Automate
- File name: Martingale_Forex.algo
- Rating: 1.67
- Installs: 8913
- Modified: 13/10/2021 09:54
Comments
@aysos75 Nice job. After early optimization and backtesting results show some promise. The only thing I would ask is if you could add an initial volume parameter with min/max values from 0.01 - 1
thank you and keep up the good work!
Hello
Your "Martigale_Forex" strategy is pretty sound. However, I am getting two errors when I tried to compile it. They are:
1. Error CS0246: The type or namespace name 'GlobalAverageTrueRange' could not be found (are you missing a using directive or an assembly reference?)
2. Error CS0246: The type or namespace name 'DirectionalMovementSystemRating' could not be found (are you missing a using directive or an assembly reference?)
I am pretty new at programming with C Sharp, so my Learning Curve is very daunting.
Can you please help me with the solution to these errors. I did some French in High School, but never paid sufficient attention, I am now finding out most painfully.
Thanks
Harold
aysos75, thank you,
I appreciate your help with this both. Could you please make available for everyone the latest version? We find difficulty to decompile as windows OS users.
Best
hello
Can somebody explain how to do , get little error when try from github, i dont know if i do it right.
Some for dummies :) have little know how with compile :/
conny
Looks good but also cant get it work because of the Lib error. I tried to find solution from Github but french makes it very difficult to understand the instructions.
Have used your other projects and have got decent result. Thanks aysos75
If you want to compile the bot, you have to download the source on github and to read the explanations on https://github.com/abhacid/Martingale_Forex
The compiler points a Lib error, what is the problem?
sorry for the two precedents mistakes
link to myfxbook : http://www.myfxbook.com/members/abhacid/mforex-1700/1304163
You can find Candlestick Tendency II here :
link to Candlestick Tendency II
Read the information about installation here
Error CS0246: The type or namespace name 'CandlestickTendencyII' could not be found (are you missing a using directive or an assembly reference?)
where can I find CandlestickTendencyII Indicator ?
nevermind - found it as mforex on cmirror.
the cMirror instance is also missing all of a sudden...
Keep up the great work!
Hi Aysos,
First of all, thank you for sharing the robot with us. Does anyone know how to solve this problem, it is probably a basic one. Here, the algo doesn't build, instead it shows this message:
Error : Project C:\Users\Nikolas\Documents\cAlgoBots\Sources\Library\cAlgoLib\cAlgo.Lib.csproj doesn't exist.
Regards
the first link don't work clic on the second link
I made a Youtube video in french to explain how to get the Visual Studio solution from Github and how to edit and debug the robot in conjunction with cAlgo.
J'ai fait une vidéo Youtube en français pour expliquer comment récupérer la solution Visual studio à partir de Github et comment modifier et déboguer le robot en liaison avec cAlgo.
yes I have updated it
Download link is not working is not working here on CTDN - you may want top update this for the new version you have released
By the weekend I would make an instructional video to make everything work between cTDN, Github and visual studio.
Basically everything is explained on github with settings files and screenshots in a specific folder of the Visual Studio solution. The robot runs on cMiror and can be replicated on one of your demo accounts
the new copy trading reference is
salut cher monsieur
i ai testé votre robot, il est pas ce robot réel qui est téléchargé à ctrader.com
selon de mettre les fichiers à la version de robot GitHub est différente, s'il vous plaît télécharger le fichier de code réelle ou écrire la méthode comment le faire travailler, qui est disponible à github.
je suis face à trop de problèmes. aider s'il vous plaît.
Merci et salutations
cher Abdalah Hacid
Merci pour cette idée et de la partager avec tous....
J ai progressé en regardant vos codes et vos méthodes.
Je suis ok avec Hichem,j ai actuellement le même soucis avec backesting tick data....
Il y a un problème.../forum/calgo-support/5418
Cordialement
Bons Trades
Hello and thank you for the algo
The screenshot doesn't reflect reality:
The Max Risk (%) paraemter is set to be of type int, whereas in the screenshot it has a value of double.
The backtest curve is not the curve realized when using the Robot on the paraemters shown on the screenshot.
I put on Martingale_Forex on CMiror:
https://cm.spotware.com/strategy/56296
it copies the positions he takes on either a demo account is a real account.
I put on Martingale_Forex on CMiror:
https://cm.spotware.com/strategy/56296
it copies the positions he takes on either a demo account is a real account.
Hi
Now it Errer 1
Error CS0234: The type or namespace name 'Lib' does not exist in the namespace 'cAlgo' (are you missing an assembly reference?)
Who can help me?