forked from rosh/MQL5Book
284 lines
11 KiB
MQL5
284 lines
11 KiB
MQL5
//+------------------------------------------------------------------+
| |||
//| TradeHistoryPrint.mq5 |
| |||
//| Copyright 2022, MetaQuotes Ltd. |
| |||
//| https://www.mql5.com |
| |||
//| Print out positions/deal/orders from trade history |
| |||
//+------------------------------------------------------------------+
| |||
#property script_show_inputs
| |||
| |||
#include "..\..\Include\OrderFilter.mqh"
| |||
#include "..\..\Include\DealFilter.mqh"
| |||
| |||
//+------------------------------------------------------------------+
| |||
//| History selection method |
| |||
//+------------------------------------------------------------------+
| |||
enum SELECTOR_TYPE
| |||
{
| |||
TOTAL, // Whole history
| |||
POSITION, // Position ID
| |||
};
| |||
| |||
input SELECTOR_TYPE Type = TOTAL;
| |||
input ulong PositionID = 0; // Position ID
| |||
| |||
//+------------------------------------------------------------------+
| |||
//| Custom tuple for pretty-printing deal properties |
| |||
//| First field must have name '_1' to be compatible with Filters |
| |||
//+------------------------------------------------------------------+
| |||
struct DealTuple
| |||
{
| |||
datetime _1; // deal time
| |||
ulong deal;
| |||
ulong order;
| |||
string type;
| |||
string in_out;
| |||
double volume;
| |||
double price;
| |||
double profit;
| |||
| |||
static int size() { return 8; }; // number of properties
| |||
static const int fields[]; // identifiers of requested deal properties
| |||
| |||
template<typename M> // M should be MonitorInterface<>
| |||
void assign(M &m)
| |||
{
| |||
static const int DEAL_TYPE_ = StringLen("DEAL_TYPE_");
| |||
static const int DEAL_ENTRY_ = StringLen("DEAL_ENTRY_");
| |||
static const ulong L = 0; // default type declarator (dummy)
| |||
| |||
_1 = (datetime)m.get(fields[0], L);
| |||
deal = m.get(fields[1], deal);
| |||
order = m.get(fields[2], order);
| |||
const ENUM_DEAL_TYPE t = (ENUM_DEAL_TYPE)m.get(fields[3], L);
| |||
type = StringSubstr(EnumToString(t), DEAL_TYPE_);
| |||
const ENUM_DEAL_ENTRY e = (ENUM_DEAL_ENTRY)m.get(fields[4], L);
| |||
in_out = StringSubstr(EnumToString(e), DEAL_ENTRY_);
| |||
volume = m.get(fields[5], volume);
| |||
price = m.get(fields[6], price);
| |||
profit = m.get(fields[7], profit);
| |||
}
| |||
};
| |||
| |||
static const int DealTuple::fields[] =
| |||
{
| |||
DEAL_TIME, DEAL_TICKET, DEAL_ORDER, DEAL_TYPE,
| |||
DEAL_ENTRY, DEAL_VOLUME, DEAL_PRICE, DEAL_PROFIT
| |||
};
| |||
| |||
//+------------------------------------------------------------------+
| |||
//| Custom tuple for pretty-printing order properties |
| |||
//| First field must have name '_1' to be compatible with Filters |
| |||
//+------------------------------------------------------------------+
| |||
struct OrderTuple
| |||
{
| |||
ulong _1; // ticket (and 'ulong' type declarator)
| |||
datetime setup;
| |||
datetime done;
| |||
string type;
| |||
double volume;
| |||
double open;
| |||
double current;
| |||
double sl;
| |||
double tp;
| |||
string comment;
| |||
| |||
static int size() { return 10; }; // number of properties
| |||
static const int fields[]; // identifiers of requested order properties
| |||
| |||
template<typename M> // M should be MonitorInterface<>
| |||
void assign(M &m)
| |||
{
| |||
static const int ORDER_TYPE_ = StringLen("ORDER_TYPE_");
| |||
| |||
_1 = m.get(fields[0], _1);
| |||
setup = (datetime)m.get(fields[1], _1);
| |||
done = (datetime)m.get(fields[2], _1);
| |||
const ENUM_ORDER_TYPE t = (ENUM_ORDER_TYPE)m.get(fields[3], _1);
| |||
type = StringSubstr(EnumToString(t), ORDER_TYPE_);
| |||
volume = m.get(fields[4], volume);
| |||
open = m.get(fields[5], open);
| |||
current = m.get(fields[6], current);
| |||
sl = m.get(fields[7], sl);
| |||
tp = m.get(fields[8], tp);
| |||
comment = m.get(fields[9], comment);
| |||
}
| |||
};
| |||
| |||
static const int OrderTuple::fields[] =
| |||
{
| |||
ORDER_TICKET, ORDER_TIME_SETUP, ORDER_TIME_DONE, ORDER_TYPE, ORDER_VOLUME_INITIAL,
| |||
ORDER_PRICE_OPEN, ORDER_PRICE_CURRENT, ORDER_SL, ORDER_TP, ORDER_COMMENT
| |||
};
| |||
| |||
//+------------------------------------------------------------------+
| |||
//| Help function to remove duplicates from array |
| |||
//+------------------------------------------------------------------+
| |||
template<typename T>
| |||
int ArrayUnique(T &array[], const T empty = (T)NULL)
| |||
{
| |||
const int n = ArraySize(array);
| |||
for(int i = 1; i < n; ++i)
| |||
{
| |||
if(array[i] == array[i - 1])
| |||
{
| |||
array[i - 1] = empty;
| |||
}
| |||
}
| |||
| |||
int i = 0, w = 0;
| |||
while(i < n)
| |||
{
| |||
while(i < n && array[i] == empty)
| |||
{
| |||
i++;
| |||
}
| |||
| |||
while(i < n && array[i] != empty)
| |||
{
| |||
if(w < i)
| |||
{
| |||
array[w] = array[i];
| |||
}
| |||
i++;
| |||
w++;
| |||
}
| |||
}
| |||
return n - ArrayResize(array, w);
| |||
}
| |||
| |||
//+------------------------------------------------------------------+
| |||
//| Script program start function |
| |||
//+------------------------------------------------------------------+
| |||
void OnStart()
| |||
{
| |||
// filter objects for deals and orders
| |||
DealFilter filter;
| |||
HistoryOrderFilter subfilter;
| |||
| |||
// select specific history
| |||
if(PositionID == 0 || Type == TOTAL)
| |||
{
| |||
HistorySelect(0, LONG_MAX);
| |||
}
| |||
else if(Type == POSITION)
| |||
{
| |||
HistorySelectByPosition(PositionID);
| |||
}
| |||
| |||
// collect position IDs (all or a given single one)
| |||
ulong positions[];
| |||
if(PositionID == 0)
| |||
{
| |||
ulong tickets[];
| |||
filter.let(DEAL_SYMBOL, _Symbol).select(DEAL_POSITION_ID, tickets, positions, true);
| |||
ArrayUnique(positions);
| |||
}
| |||
else
| |||
{
| |||
PUSH(positions, PositionID);
| |||
}
| |||
| |||
const int n = ArraySize(positions);
| |||
Print("Positions total: ", n);
| |||
if(n == 0) return;
| |||
| |||
// show all positions: deals and orders
| |||
for(int i = 0; i < n; ++i)
| |||
{
| |||
DealTuple deals[];
| |||
filter.let(DEAL_POSITION_ID, positions[i]).select(deals, true);
| |||
const int m = ArraySize(deals);
| |||
if(m == 0)
| |||
{
| |||
Print("Wrong position ID: ", positions[i]);
| |||
break; // wrong position id specfied by user
| |||
}
| |||
double profit = 0; // TODO: consider commissons, swaps and fees, if needed
| |||
for(int j = 0; j < m; ++j) profit += deals[j].profit;
| |||
PrintFormat("Position: % 8d %16lld Profit:%f", i + 1, positions[i], (profit));
| |||
ArrayPrint(deals);
| |||
| |||
// NB: 'close-by' orders will be listed on both positions
| |||
// only if 'Whole history' is selected, because otherwise
| |||
// HistorySelectByPosition is used
| |||
// which selects 'close-by' order only by one side
| |||
| |||
Print("Order details:");
| |||
OrderTuple orders[];
| |||
subfilter.let(ORDER_POSITION_ID, positions[i], IS::OR_EQUAL)
| |||
.let(ORDER_POSITION_BY_ID, positions[i], IS::OR_EQUAL)
| |||
.select(orders);
| |||
ArrayPrint(orders);
| |||
}
| |||
}
| |||
//+------------------------------------------------------------------+
| |||
/*
| |||
EXAMPLE 1 (default settings)
| |||
| |||
Positions total: 3
| |||
Position: 1 1253500309 Profit:238.150000
| |||
[_1] [deal] [order] [type] [in_out] [volume] [price] [profit]
| |||
[0] 2022.02.04 17:34:57 1236049891 1253500309 "BUY" "IN" 1.00000 76.23900 0.00000
| |||
[1] 2022.02.14 16:28:41 1242295527 1259788704 "SELL" "OUT" 1.00000 76.42100 238.15000
| |||
Order details:
| |||
[_1] [setup] [done] [type] [volume] [open] [current] [sl] [tp] [comment]
| |||
[0] 1253500309 2022.02.04 17:34:57 2022.02.04 17:34:57 "BUY" 1.00000 76.23900 76.23900 0.00 0.00 ""
| |||
[1] 1259788704 2022.02.14 16:28:41 2022.02.14 16:28:41 "SELL" 1.00000 76.42100 76.42100 0.00 0.00 ""
| |||
Position: 2 1253526613 Profit:878.030000
| |||
[_1] [deal] [order] [type] [in_out] [volume] [price] [profit]
| |||
[0] 2022.02.07 10:00:00 1236611994 1253526613 "BUY" "IN" 1.00000 75.75000 0.00000
| |||
[1] 2022.02.14 16:28:40 1242295517 1259788693 "SELL" "OUT" 1.00000 76.42100 878.03000
| |||
Order details:
| |||
[_1] [setup] [done] [type] [volume] [open] [current] [sl] [tp] [comment]
| |||
[0] 1253526613 2022.02.04 17:55:18 2022.02.07 10:00:00 "BUY_LIMIT" 1.00000 75.75000 75.67000 0.00 0.00 ""
| |||
[1] 1259788693 2022.02.14 16:28:40 2022.02.14 16:28:40 "SELL" 1.00000 76.42100 76.42100 0.00 0.00 ""
| |||
Position: 3 1256280710 Profit:4449.040000
| |||
[_1] [deal] [order] [type] [in_out] [volume] [price] [profit]
| |||
[0] 2022.02.09 13:17:52 1238797056 1256280710 "BUY" "IN" 2.00000 74.72100 0.00000
| |||
[1] 2022.02.14 16:28:39 1242295509 1259788685 "SELL" "OUT" 2.00000 76.42100 4449.04000
| |||
Order details:
| |||
[_1] [setup] [done] [type] [volume] [open] [current] [sl] [tp] [comment]
| |||
[0] 1256280710 2022.02.09 13:17:52 2022.02.09 13:17:52 "BUY" 2.00000 74.72100 74.72100 0.00 0.00 ""
| |||
[1] 1259788685 2022.02.14 16:28:39 2022.02.14 16:28:39 "SELL" 2.00000 76.42100 76.42100 0.00 0.00 ""
| |||
| |||
| |||
EXAMPLE 2 (PositionID=1276109280, Type=Whole history/Position)
| |||
| |||
Positions total: 1
| |||
Position: 1 1276109280 Profit:-0.040000
| |||
[_1] [deal] [order] [type] [in_out] [volume] [price] [profit]
| |||
[0] 2022.03.07 12:20:53 1258725455 1276109280 "BUY" "IN" 0.01000 1.08344 0.00000
| |||
[1] 2022.03.07 12:20:58 1258725503 1276109328 "SELL" "OUT_BY" 0.01000 1.08340 -0.04000
| |||
Order details:
| |||
[_1] [setup] [done] [type] [volume] [open] [current] [sl] [tp] [comment]
| |||
[0] 1276109280 2022.03.07 12:20:53 2022.03.07 12:20:53 "BUY" 0.01000 1.08344 1.08344 0.00 0.00 ""
| |||
[1] 1276109328 2022.03.07 12:20:58 2022.03.07 12:20:58 "CLOSE_BY" 0.01000 1.08340 1.08340 0.00 0.00 "#1276109280 by #1276109283"
| |||
| |||
| |||
EXAMPLE 3 (PositionID=1276109283, Type=Position) - note that exit order (1276109328) is missing
| |||
| |||
Positions total: 1
| |||
Position: 1 1276109283 Profit:0.000000
| |||
[_1] [deal] [order] [type] [in_out] [volume] [price] [profit]
| |||
[0] 2022.03.07 12:20:53 1258725458 1276109283 "SELL" "IN" 0.01000 1.08340 0.00000
| |||
[1] 2022.03.07 12:20:58 1258725504 1276109328 "BUY" "OUT_BY" 0.01000 1.08344 0.00000
| |||
Order details:
| |||
[_1] [setup] [done] [type] [volume] [open] [current] [sl] [tp] [comment]
| |||
[0] 1276109283 2022.03.07 12:20:53 2022.03.07 12:20:53 "SELL" 0.01000 1.08340 1.08340 0.00 0.00 ""
| |||
| |||
| |||
EXAMPLE 4 (PositionID=1276109283, Type=Whole history) - note that exit order is present
| |||
| |||
Positions total: 1
| |||
Position: 1 1276109283 Profit:0.000000
| |||
[_1] [deal] [order] [type] [in_out] [volume] [price] [profit]
| |||
[0] 2022.03.07 12:20:53 1258725458 1276109283 "SELL" "IN" 0.01000 1.08340 0.00000
| |||
[1] 2022.03.07 12:20:58 1258725504 1276109328 "BUY" "OUT_BY" 0.01000 1.08344 0.00000
| |||
Order details:
| |||
[_1] [setup] [done] [type] [volume] [open] [current] [sl] [tp] [comment]
| |||
[0] 1276109283 2022.03.07 12:20:53 2022.03.07 12:20:53 "SELL" 0.01000 1.08340 1.08340 0.00 0.00 ""
| |||
[1] 1276109328 2022.03.07 12:20:58 2022.03.07 12:20:58 "CLOSE_BY" 0.01000 1.08340 1.08340 0.00 0.00 "#1276109280 by #1276109283"
| |||
| |||
| |||
*/
| |||
//+------------------------------------------------------------------+
|