В жизни бывают такие моменты, когда очень хочется торговать из программы на
С++, но по каким-то причинам у брокера нет
API, зато есть
MetaTrader. Конечно, можно просто писать код на
MQL4/MQL5, на этом урезанном варианте-мутанте
Си и
С++, но мне как-то не в кайф это делать. Поэтому я решил сделать «мост» между
MetaTrader и программой через socket. Встречайте —
MT-Bridge.
На данный момент
MT-Bridge позволяет только передавать поток котировок в программу с заданной частотой + добавлена инициализация исторических данных. Пока мне этого достаточно, но возможно в будущем функционал
MT-Bridge будет расширен. Поэтому извиняйте, если здесь вы не нашли полноценного функционала, что есть то есть пока. Библиотека для подключения к советнику написана на
С++11 и зависит от
boost.asio, но нужны только файлы-заголовки. Вот
github репозиторий с советником и библиотекой. Передача данных реализована через сокеты, советник является клинетом, а программа на С++ — сервером. Данные передаются через сокет в бинарном виде.
Как пользоваться
В терминале MetTrader нужно добавить советник
MT-Bridge на график. Советнику нужно разрешить использовать dll.
Настройки советника:
- Server hostname or IP address — Имя хоста, по умолчанию localhost
- Server port — Порт сервера, по умолчанию 5555
- Array of used currency pairs — Массив имен валютны пар, данные которых должен передавать советник. По умолчанию представлен следующий список: EURUSD,USDJPY,GBPUSD,USDCHF,USDCAD,EURJPY,AUDUSD,NZDUSD, EURGBP,EURCHF,AUDJPY,GBPJPY,CHFJPY,EURCAD,AUDCAD,CADJPY, NZDJPY,AUDNZD,GBPAUD,EURAUD,GBPCHF,EURNZD,AUDCHF,GBPNZD, GBPCAD,XAUUSD
- Data update period (milliseconds) — Период обновления данных (в миллисекундах). Чем меньше это время, тем чаще будут поступать данные на сервер.
- Depth of history to initialize — Глубина исторических данных во время инициализации. Это количество баров, которое будет передано на сервер во время подключения.
Затем нужно написать программу, в которой подключить
header-only библиотеку mt-bridge.hpp
Программа будет пытаться установить связь с советником. Можно использовать метод
wait(), чтобы дождаться соединения. После установки соединения можно получать поток котировок, получить список используемых валютных пар или обратиться к небольшому промежутку исторических данных, которые передал советник при подключении.
Пример кода
Данный код после подключения к эксперту выведет на экран список символов, затем выведет исторические данные баров нулевого символа и после этого будет показывать текущую цену ask, цену закрытия бара, объем бара, время открытия бара и время сервера.
#include <iostream>
#include <mt-bridge.hpp>
int main() {
const uint32_t port = 5555;
mt_bridge::MtBridge iMT(port);
if(!iMT.wait()) {
std::cout << "no connection" << std::endl;
return 0;
}
std::cout << "connection established" << std::endl;
const uint32_t DELAY_WAIT = 5000;
std::this_thread::sleep_for(std::chrono::milliseconds(DELAY_WAIT));
/* list all symbols */
std::vector<std::string> symbol_list = iMT.get_symbol_list();
std::for_each(symbol_list.begin(), symbol_list.end(), [&](std::string &symbol) {
static int n = 0;
std::cout
<< "symbol["
<< std::to_string(n++)
<< "]: "
<< symbol
<< std::endl;
});
std::cout << "mt-bridge version: " << iMT.get_mt_bridge_version() << std::endl;
std::this_thread::sleep_for(std::chrono::milliseconds(DELAY_WAIT));
const uint32_t symbol_index = 0; // first symbol in the list
/* get historical data to initialize your indicators */
std::cout << iMT.get_symbol_list()[symbol_index] << std::endl;
std::vector<mt_bridge::MtCandle> candles = iMT.get_candles(symbol_index);
for(size_t i = 0; i < candles.size(); ++i) {
std::cout << "candle, o: " << candles[i].open
<< " h: " << candles[i].high
<< " l: " << candles[i].low
<< " c: " << candles[i].close
<< " v: " << candles[i].volume
<< " t: " << candles[i].timestamp
<< std::endl;
}
std::this_thread::sleep_for(std::chrono::milliseconds(DELAY_WAIT));
/* quotations stream */
while(true) {
if(!iMT.update_server_timestamp()) continue;
mt_bridge::MtCandle candle = iMT.get_candle(symbol_index);
std::cout
<< iMT.get_symbol_list()[symbol_index]
<< " candle,"
<< " ask: " << iMT.get_ask(symbol_index)
<< " c: " << candle.close
<< " v: " << candle.volume
<< " t: " << candle.timestamp
<< " s: " << iMT.get_server_timestamp()
<< std::endl;
}
return 0;
}
Зависимости
- boost.asio (нужны только заголовочные файлы)
- для компилятора mingw добавить библиотеки ws2_32 и wsock32
Может кому пригодится)
можно было сделать на базе Com(DCOM) сервера.
за основу взять например из экселя интерфейсы IRtdServer & IRTDUpdateEvent
… по крайней мере не надо было бы с бинарными данными возиться)