548 lines
17 KiB
MQL5
548 lines
17 KiB
MQL5
//+------------------------------------------------------------------+
|
|
//| MTBalancer.mqh |
|
|
//| Copyright 2018, MetaQuotes Software Corp. |
|
|
//| https://www.mql5.com |
|
|
//+------------------------------------------------------------------+
|
|
#property library
|
|
#property version "1.7";
|
|
|
|
#include <Generic\SortedMap.mqh>
|
|
#include <Trade\Trade.mqh>
|
|
#include <Trade\AccountInfo.mqh>
|
|
#include <Files\File.mqh>
|
|
|
|
CAccountInfo account;
|
|
CTrade trade;
|
|
|
|
|
|
#define ASK NormalizeDouble(SymbolInfoDouble(_Symbol, SYMBOL_ASK), _Digits)
|
|
#define BID NormalizeDouble(SymbolInfoDouble(_Symbol, SYMBOL_BID), _Digits)
|
|
#define PRICE NormalizeDouble((ASK+BID)/2, _Digits)
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
void place_a_long(double price, int take_profit, int volume_mult=1, int stop_loss=0)
|
|
{
|
|
double Ask = price;
|
|
double t_stop_loss = 0;
|
|
|
|
if(stop_loss>0)
|
|
{
|
|
t_stop_loss = Ask-stop_loss*_Point;
|
|
}
|
|
|
|
trade.Buy(
|
|
0.10*volume_mult, // Volume, in this case 10 mini lost or .1 std-lot
|
|
NULL, // symbol im running from ( most of my run are done in the EURUSD)
|
|
Ask, // Buying price ... since buy, its done using the ask for this case
|
|
t_stop_loss, // stop-loss, this should be ignored in this case ... we will see
|
|
Ask+take_profit*_Point, // take profit ( this is our band activation for the box
|
|
NULL // this is a comment
|
|
);
|
|
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
void place_a_short(double price, int take_profit, int volume_mult=1, int stop_loss=0)
|
|
{
|
|
double Bid = price;
|
|
double t_stop_loss = 0;
|
|
if(stop_loss > 0)
|
|
{
|
|
t_stop_loss = Bid+stop_loss*_Point;
|
|
}
|
|
trade.Sell(0.10*volume_mult, NULL, Bid, t_stop_loss, Bid-take_profit*_Point, NULL);
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Sorting done by least - to - most profitable
|
|
//| Also will mean that (more to less costly positions)
|
|
//+------------------------------------------------------------------+
|
|
void SortedPositions(int &buffer[])
|
|
{
|
|
CSortedMap<double, int> s_positions;
|
|
for(int i=PositionsTotal()-1; i>=0; i--)
|
|
{
|
|
int ticket = (int)PositionGetTicket(i);
|
|
double profit = PositionGetDouble(POSITION_PROFIT);
|
|
s_positions.Add(profit, ticket);
|
|
}
|
|
double keys[];
|
|
|
|
s_positions.CopyTo(keys, buffer, 0);
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
int GetHighestCostPosition(bool isLong=true)
|
|
{
|
|
int s_positions[];
|
|
SortedPositions(s_positions);
|
|
|
|
|
|
for(int i=0; i<ArraySize(s_positions); i++)
|
|
{
|
|
int ticket = s_positions[i];
|
|
PositionSelectByTicket(ticket);
|
|
if(isLong)
|
|
{
|
|
if(PositionGetInteger(POSITION_TYPE)== POSITION_TYPE_BUY)
|
|
{
|
|
return ticket;
|
|
}
|
|
}
|
|
|
|
else
|
|
{
|
|
if(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_SELL)
|
|
{
|
|
return ticket;
|
|
}
|
|
}
|
|
|
|
}
|
|
return -1; // if this where to happen there must be an error
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
int GetLowestCostPosition(bool isLong=true)
|
|
{
|
|
int s_positions[];
|
|
SortedPositions(s_positions);
|
|
|
|
|
|
for(int i=ArraySize(s_positions)-1; i>=0; i--)
|
|
{
|
|
int ticket = s_positions[i];
|
|
PositionSelectByTicket(ticket);
|
|
if(isLong)
|
|
{
|
|
if(PositionGetInteger(POSITION_TYPE)== POSITION_TYPE_BUY)
|
|
{
|
|
return ticket;
|
|
}
|
|
}
|
|
|
|
else
|
|
{
|
|
if(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_SELL)
|
|
{
|
|
return ticket;
|
|
}
|
|
}
|
|
|
|
}
|
|
return -1; // if this where to happen there is an error!
|
|
}
|
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
double GetVolume(bool isLong=true)
|
|
{
|
|
double Total_Volume = 0;
|
|
for(int i=0; i<=PositionsTotal(); i++)
|
|
{
|
|
int ticket = (int)PositionGetTicket(i);
|
|
PositionSelectByTicket(ticket);
|
|
if(isLong)
|
|
{
|
|
if(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY)
|
|
{
|
|
Total_Volume += PositionGetDouble(POSITION_VOLUME);
|
|
}
|
|
}
|
|
else
|
|
if(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_SELL)
|
|
{
|
|
Total_Volume += PositionGetDouble(POSITION_VOLUME);
|
|
}
|
|
|
|
|
|
}
|
|
return Total_Volume;
|
|
}
|
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
void close_all_positions()
|
|
{
|
|
for(int i=PositionsTotal()-1 ; i>= 0 ; i--)
|
|
{
|
|
int ticket = (int)PositionGetTicket(i);
|
|
trade.PositionClose(ticket);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
double GetVolumeDifference(bool wDirection=false)
|
|
{
|
|
if(wDirection)
|
|
{
|
|
return GetVolumeInLong() - GetVolumeInShort();
|
|
}
|
|
return fabs(GetVolumeInLong() - GetVolumeInShort());
|
|
}
|
|
|
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
double GetVolumeInShort()
|
|
{
|
|
return GetVolume(false);
|
|
}
|
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
double GetVolumeInLong()
|
|
{
|
|
return GetVolume(true);
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
double depositLoad()
|
|
{
|
|
return (account.Margin() / account.Balance()) * 100;
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
int CountPositionsByType(bool isLong=true)
|
|
{
|
|
int long_count=0, short_count=0;
|
|
for(int i=PositionsTotal() -1 ; i>=0; i--)
|
|
{
|
|
PositionSelectByTicket(PositionGetTicket(i));
|
|
if(PositionGetInteger(POSITION_TYPE)==POSITION_TYPE_BUY)
|
|
{
|
|
long_count ++;
|
|
}
|
|
else
|
|
{
|
|
short_count ++;
|
|
}
|
|
|
|
}
|
|
if(isLong)
|
|
{
|
|
return long_count;
|
|
}
|
|
return short_count;
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
int PositionDifferenceByType(bool wDirrection=false)
|
|
{
|
|
int long_c= CountPositionsByType();
|
|
int short_c=CountPositionsByType(false);
|
|
if(wDirrection)
|
|
{
|
|
return fabs(long_c - short_c);
|
|
}
|
|
return (long_c - short_c);
|
|
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
double GetHigestPositionOpenPrice()
|
|
{
|
|
double result=-1;
|
|
for(int i=0; i< PositionsTotal(); i++)
|
|
{
|
|
long ticket = (int)PositionGetTicket(i);
|
|
PositionSelectByTicket(ticket);
|
|
double new_price = PositionGetDouble(POSITION_PRICE_OPEN);
|
|
if(new_price>result)
|
|
{
|
|
result = new_price;
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
double GetLowestPositionOpenPrice()
|
|
{
|
|
double result=-1;
|
|
for(int i=0; i< PositionsTotal(); i++)
|
|
{
|
|
long ticket = (int)PositionGetTicket(i);
|
|
PositionSelectByTicket(ticket);
|
|
double new_price = PositionGetDouble(POSITION_PRICE_OPEN);
|
|
if(new_price<result || result == -1)
|
|
{
|
|
result = new_price;
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
void CloseAllShorts()
|
|
{
|
|
for(int i=PositionsTotal()-1 ; i>= 0 ; i--)
|
|
{
|
|
int ticket = (int)PositionGetTicket(i);
|
|
PositionSelectByTicket(ticket);
|
|
if(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_SELL)
|
|
{
|
|
trade.PositionClose(ticket);
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
void CloseAllLongs()
|
|
{
|
|
for(int i=PositionsTotal()-1 ; i>= 0 ; i--)
|
|
{
|
|
int ticket = (int)PositionGetTicket(i);
|
|
PositionSelectByTicket(ticket);
|
|
if(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY)
|
|
{
|
|
trade.PositionClose(ticket);
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
double GetPositionSizeByRisk(double risk_percent, int stop_loss,double price)
|
|
{
|
|
// pip_at_risk * pip_value * lots_traded = amount to risk
|
|
//amount_at_risk / (pip_at_risk * pip_value) = lots
|
|
double amount_to_risk = account.Balance() * risk_percent;
|
|
double pips_to_risk = stop_loss;
|
|
double pip_value = (0.0001 * 100000) / price;
|
|
double lots_to_trade = amount_to_risk / (pips_to_risk * pip_value);
|
|
|
|
return NormalizeDouble(lots_to_trade, 2);
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
void PlaceLongPosition(int take_profit, int stop_loss, double risk_percent)
|
|
{
|
|
double volume = GetPositionSizeByRisk(risk_percent, stop_loss, BID);
|
|
double position_sl = NormalizeDouble(ASK - (stop_loss*_Point), _Digits);
|
|
double positons_tp = NormalizeDouble(ASK + (take_profit*_Point), _Digits);
|
|
trade.Buy(volume, _Symbol, ASK, position_sl, positons_tp, NULL);
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
void PlaceShortPosition(int take_profit, int stop_loss, double risk_percent)
|
|
{
|
|
double volume = GetPositionSizeByRisk(risk_percent, stop_loss, BID);
|
|
double position_sl = NormalizeDouble(BID + (stop_loss*_Point), _Digits);
|
|
double positons_tp = NormalizeDouble(BID - (take_profit*_Point), _Digits);
|
|
trade.Sell(volume, _Symbol, BID, position_sl, positons_tp, NULL);
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
bool HasReachedPriceChange(double base_price, double curr_price, int pip_change)
|
|
{
|
|
double pip_difference = fabs(base_price - curr_price);
|
|
Print("Looking Inside: ", StringFormat("%2.5f | %2.5f | %2.5f", base_price, curr_price, pip_difference));
|
|
if(pip_difference > (120*_Point))
|
|
{
|
|
Print("Difference: ", pip_difference);
|
|
}
|
|
return pip_difference >= (pip_change * _Point);
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
class HTTPAccountLog
|
|
{
|
|
|
|
private:
|
|
string address;
|
|
int port;
|
|
int socket;
|
|
CAccountInfo account;
|
|
|
|
bool httpSend(string request)
|
|
{
|
|
char req[];
|
|
int len = StringToCharArray(request, req)-1;
|
|
if(len<0)
|
|
return false;
|
|
else
|
|
return(SocketSend(socket,req,len)==len);
|
|
}
|
|
|
|
double deposit_load()
|
|
{
|
|
return (account.Margin()/ account.Equity()) * 100;
|
|
}
|
|
|
|
public:
|
|
void log_data()
|
|
{
|
|
string dl = "\"deposit_load\" : \"" + deposit_load()+ "\"";
|
|
string date = "\"date\" : \""+ TimeToString(TimeCurrent())+ "\"";
|
|
string equity = "\"equity\" : \"" + account.Equity() + "\"";
|
|
string json_req = StringFormat("{ %s , %s , %s}", dl,date,equity);
|
|
|
|
|
|
string http_request_tmplt = "POST %s HTTP/1.1\r\nHost: %s:%d\r\nContent-Type: application/json\r\nContent-Length: %d\r\n\r\n %s";
|
|
string http_request = StringFormat(http_request_tmplt, "/upload/01", address, port, StringLen(json_req), json_req);
|
|
|
|
bool resp = httpSend(http_request);
|
|
if(resp)
|
|
{
|
|
Print("Could write to server");
|
|
}
|
|
else
|
|
{
|
|
Print("failed writing to server ...");
|
|
}
|
|
|
|
}
|
|
void AccountLog(void)
|
|
{
|
|
socket = SocketCreate();
|
|
address = "127.0.0.1";
|
|
port = 5001;
|
|
account = CAccountInfo();
|
|
}
|
|
|
|
void closeConnect(void)
|
|
{
|
|
SocketClose(socket);
|
|
}
|
|
};
|
|
|
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
class AccountLog
|
|
{
|
|
|
|
private:
|
|
string foldername;
|
|
string filename;
|
|
string ffilename;
|
|
CFile fp;
|
|
CAccountInfo account;
|
|
|
|
double max_deposit_load;
|
|
double min_deposit_load;
|
|
datetime start_date;
|
|
|
|
|
|
|
|
double deposit_load(void)
|
|
{
|
|
return (account.Margin()/ account.Equity()) * 100;
|
|
}
|
|
|
|
public:
|
|
|
|
void store_log(void)
|
|
{
|
|
double crr_deposit_load = deposit_load();
|
|
if(crr_deposit_load > max_deposit_load)
|
|
{
|
|
max_deposit_load = crr_deposit_load;
|
|
}
|
|
else
|
|
if(crr_deposit_load < min_deposit_load)
|
|
{
|
|
min_deposit_load = crr_deposit_load;
|
|
}
|
|
|
|
}
|
|
void write_log(void)
|
|
{
|
|
|
|
fp.Open(ffilename, FILE_WRITE|FILE_READ|FILE_ANSI|FILE_CSV|FILE_COMMON, ',');
|
|
fp.Seek(0, SEEK_END);
|
|
FileWrite(fp.Handle(), "min_deposit_load", min_deposit_load, "max_deposit_load", max_deposit_load, "deposit_load", deposit_load(), "start_date", start_date, "end_date", TimeToString(TimeCurrent()), "equity", account.Equity());
|
|
fp.Close();
|
|
}
|
|
|
|
void AccountLog(void)
|
|
{
|
|
foldername = "LogReport";
|
|
filename = "report_01_03.csv";
|
|
ffilename = foldername+"\\"+filename;
|
|
account = CAccountInfo();
|
|
fp = CFile();
|
|
|
|
max_deposit_load = -1;
|
|
min_deposit_load = 999;
|
|
start_date = TimeCurrent();
|
|
|
|
}
|
|
void AccountLog(string nfilename)
|
|
{
|
|
foldername = "LogReport";
|
|
filename = nfilename;
|
|
ffilename = foldername+"\\"+filename;
|
|
account = CAccountInfo();
|
|
fp = CFile();
|
|
|
|
max_deposit_load = -1;
|
|
min_deposit_load = 999;
|
|
start_date = TimeCurrent();
|
|
}
|
|
|
|
};
|
|
//+------------------------------------------------------------------+
|