mirror of
https://github.com/vdemydiuk/mtapi.git
synced 2026-08-08 08:27:50 +00:00
PyMtApi5: implemented function SymbolInfoString; formatted code.
This commit is contained in:
@@ -38,6 +38,7 @@ class Mt5ApiApp:
|
|||||||
"SymbolIsSynchronized": self.process_symbol_is_synchronized,
|
"SymbolIsSynchronized": self.process_symbol_is_synchronized,
|
||||||
"SymbolInfoDouble": self.process_symbol_info_double,
|
"SymbolInfoDouble": self.process_symbol_info_double,
|
||||||
"SymbolInfoInteger": self.process_symbol_info_integer,
|
"SymbolInfoInteger": self.process_symbol_info_integer,
|
||||||
|
"SymbolInfoString": self.process_symbol_info_string,
|
||||||
}
|
}
|
||||||
|
|
||||||
def on_disconnect(self, error_msg=None):
|
def on_disconnect(self, error_msg=None):
|
||||||
@@ -204,6 +205,16 @@ class Mt5ApiApp:
|
|||||||
result = mtapi.symbol_info_integer(symbol, prop_id)
|
result = mtapi.symbol_info_integer(symbol, prop_id)
|
||||||
print(f"> SymbolInfoInteger: response = {result}")
|
print(f"> SymbolInfoInteger: response = {result}")
|
||||||
|
|
||||||
|
def process_symbol_info_string(self, mtapi, parameters):
|
||||||
|
pieces = parameters.split(" ", 1)
|
||||||
|
if len(pieces) != 2 or not pieces[0] or not pieces[1]:
|
||||||
|
print(f"! Invalid parameters for command SymbolInfoString: {parameters}")
|
||||||
|
return
|
||||||
|
symbol = pieces[0]
|
||||||
|
prop_id = mt5enums.ENUM_SYMBOL_INFO_STRING(int(pieces[1]))
|
||||||
|
result = mtapi.symbol_info_string(symbol, prop_id)
|
||||||
|
print(f"> SymbolInfoString: response = {result}")
|
||||||
|
|
||||||
def mtapi_command_thread(self, mtapi):
|
def mtapi_command_thread(self, mtapi):
|
||||||
while mtapi.is_connected():
|
while mtapi.is_connected():
|
||||||
filename = "client.cmd"
|
filename = "client.cmd"
|
||||||
|
|||||||
+61
-79
@@ -1,11 +1,12 @@
|
|||||||
|
import asyncio
|
||||||
import json
|
import json
|
||||||
import logging
|
import logging
|
||||||
import asyncio
|
|
||||||
from mt5enums import *
|
|
||||||
from enum import IntEnum
|
from enum import IntEnum
|
||||||
from threading import Lock, Thread
|
from threading import Lock, Thread
|
||||||
from mtrpcclient import MtRpcClient
|
|
||||||
from mt5commandtype import Mt5CommandType
|
from mt5commandtype import Mt5CommandType
|
||||||
|
from mt5enums import *
|
||||||
|
from mtrpcclient import MtRpcClient
|
||||||
|
|
||||||
|
|
||||||
class Mt5EventType(IntEnum):
|
class Mt5EventType(IntEnum):
|
||||||
@@ -63,10 +64,12 @@ class MqlTradeTransaction:
|
|||||||
self.time_expiration = mql_trade_transaction_json["MtTimeExpiration"]
|
self.time_expiration = mql_trade_transaction_json["MtTimeExpiration"]
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return (f"deal = {self.deal}, order = {self.order}, symbol = {self.symbol}, transaction_type = {self.transaction_type}, "
|
return (
|
||||||
f"order_type = {self.order_type}, order_state = {self.order_state}, deal_type = {self.deal_type}, time_type = {self.time_type}, "
|
f"deal = {self.deal}, order = {self.order}, symbol = {self.symbol}, transaction_type = {self.transaction_type}, "
|
||||||
f"price = {self.price}, price_trigger = {self.price_trigger}, price_sl = {self.price_sl}, price_tp = {self.price_tp}, volume = {self.volume}, "
|
f"order_type = {self.order_type}, order_state = {self.order_state}, deal_type = {self.deal_type}, time_type = {self.time_type}, "
|
||||||
f"position = {self.position}, position_by = {self.position_by}, time_expiration = {self.time_expiration}")
|
f"price = {self.price}, price_trigger = {self.price_trigger}, price_sl = {self.price_sl}, price_tp = {self.price_tp}, volume = {self.volume}, "
|
||||||
|
f"position = {self.position}, position_by = {self.position_by}, time_expiration = {self.time_expiration}"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class MqlTradeRequest:
|
class MqlTradeRequest:
|
||||||
@@ -90,10 +93,12 @@ class MqlTradeRequest:
|
|||||||
# self.position_by = mql_trade_request_json["PositionBy"]
|
# self.position_by = mql_trade_request_json["PositionBy"]
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return (f"action = {self.action}, magic = {self.magic}, order = {self.order}, symbol = {self.symbol}, volume = {self.volume}, "
|
return (
|
||||||
f"price = {self.price}, stop_limit = {self.stop_limit}, sl = {self.sl}, tp = {self.tp}, deviation = {self.deviation}, "
|
f"action = {self.action}, magic = {self.magic}, order = {self.order}, symbol = {self.symbol}, volume = {self.volume}, "
|
||||||
f"order_type = {self.order_type}, type_filling = {self.type_filling}, type_time = {self.type_time}, expiration = {self.expiration}, "
|
f"price = {self.price}, stop_limit = {self.stop_limit}, sl = {self.sl}, tp = {self.tp}, deviation = {self.deviation}, "
|
||||||
f"comment = {self.comment}")
|
f"order_type = {self.order_type}, type_filling = {self.type_filling}, type_time = {self.type_time}, expiration = {self.expiration}, "
|
||||||
|
f"comment = {self.comment}"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class MqlTradeResult:
|
class MqlTradeResult:
|
||||||
@@ -109,8 +114,10 @@ class MqlTradeResult:
|
|||||||
self.request_id = mql_trade_result_json["Request_id"]
|
self.request_id = mql_trade_result_json["Request_id"]
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return (f"retcode = {self.retcode}, deal = {self.deal}, order = {self.order}, volume = {self.volume}, price = {self.price}, "
|
return (
|
||||||
f"bid = {self.bid}, ask = {self.ask}, comment = {self.comment}, request_id = {self.request_id}")
|
f"retcode = {self.retcode}, deal = {self.deal}, order = {self.order}, volume = {self.volume}, price = {self.price}, "
|
||||||
|
f"bid = {self.bid}, ask = {self.ask}, comment = {self.comment}, request_id = {self.request_id}"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class Mt5ApiClient:
|
class Mt5ApiClient:
|
||||||
@@ -176,20 +183,17 @@ class Mt5ApiClient:
|
|||||||
# AccountInfoDouble
|
# AccountInfoDouble
|
||||||
def account_info_double(self, property_id: ENUM_ACCOUNT_INFO_DOUBLE):
|
def account_info_double(self, property_id: ENUM_ACCOUNT_INFO_DOUBLE):
|
||||||
cmd_params = {"PropertyId": property_id}
|
cmd_params = {"PropertyId": property_id}
|
||||||
return self.__send_command(
|
return self.__send_command(self.__get_default_expert(), Mt5CommandType.AccountInfoDouble, cmd_params)
|
||||||
self.__get_default_expert(), Mt5CommandType.AccountInfoDouble, cmd_params)
|
|
||||||
|
|
||||||
# AccountInfoInteger
|
# AccountInfoInteger
|
||||||
def account_info_integer(self, property_id: ENUM_ACCOUNT_INFO_INTEGER):
|
def account_info_integer(self, property_id: ENUM_ACCOUNT_INFO_INTEGER):
|
||||||
cmd_params = {"PropertyId": property_id}
|
cmd_params = {"PropertyId": property_id}
|
||||||
return self.__send_command(
|
return self.__send_command(self.__get_default_expert(), Mt5CommandType.AccountInfoInteger, cmd_params)
|
||||||
self.__get_default_expert(), Mt5CommandType.AccountInfoInteger, cmd_params)
|
|
||||||
|
|
||||||
# AccountInfoString
|
# AccountInfoString
|
||||||
def account_info_string(self, property_id: ENUM_ACCOUNT_INFO_STRING):
|
def account_info_string(self, property_id: ENUM_ACCOUNT_INFO_STRING):
|
||||||
cmd_params = {"PropertyId": property_id}
|
cmd_params = {"PropertyId": property_id}
|
||||||
return self.__send_command(
|
return self.__send_command(self.__get_default_expert(), Mt5CommandType.AccountInfoString, cmd_params)
|
||||||
self.__get_default_expert(), Mt5CommandType.AccountInfoString, cmd_params)
|
|
||||||
|
|
||||||
# Timeseries and Indicators Access
|
# Timeseries and Indicators Access
|
||||||
|
|
||||||
@@ -197,33 +201,27 @@ class Mt5ApiClient:
|
|||||||
def series_info_integer(self, symbol_name, timeframe: ENUM_TIMEFRAMES, prop_id: ENUM_SERIES_INFO_INTEGER):
|
def series_info_integer(self, symbol_name, timeframe: ENUM_TIMEFRAMES, prop_id: ENUM_SERIES_INFO_INTEGER):
|
||||||
if symbol_name is None:
|
if symbol_name is None:
|
||||||
symbol_name = ""
|
symbol_name = ""
|
||||||
cmd_params = {"Symbol": symbol_name,
|
cmd_params = {"Symbol": symbol_name, "Timeframe": timeframe, "PropId": prop_id}
|
||||||
"Timeframe": timeframe, "PropId": prop_id}
|
return self.__send_command(self.__get_default_expert(), Mt5CommandType.SeriesInfoInteger, cmd_params)
|
||||||
return self.__send_command(
|
|
||||||
self.__get_default_expert(), Mt5CommandType.SeriesInfoInteger, cmd_params)
|
|
||||||
|
|
||||||
# Bars
|
# Bars
|
||||||
def bars(self, symbol_name, timeframe: ENUM_TIMEFRAMES):
|
def bars(self, symbol_name, timeframe: ENUM_TIMEFRAMES):
|
||||||
if symbol_name is None:
|
if symbol_name is None:
|
||||||
symbol_name = ""
|
symbol_name = ""
|
||||||
cmd_params = {"Symbol": symbol_name, "Timeframe": timeframe}
|
cmd_params = {"Symbol": symbol_name, "Timeframe": timeframe}
|
||||||
return self.__send_command(
|
return self.__send_command(self.__get_default_expert(), Mt5CommandType.Bars, cmd_params)
|
||||||
self.__get_default_expert(), Mt5CommandType.Bars, cmd_params)
|
|
||||||
|
|
||||||
# Bars (for a specified period)
|
# Bars (for a specified period)
|
||||||
def bars_period(self, symbol_name, timeframe: ENUM_TIMEFRAMES, start_time: int, stop_time: int):
|
def bars_period(self, symbol_name, timeframe: ENUM_TIMEFRAMES, start_time: int, stop_time: int):
|
||||||
if symbol_name is None:
|
if symbol_name is None:
|
||||||
symbol_name = ""
|
symbol_name = ""
|
||||||
cmd_params = {"Symbol": symbol_name, "Timeframe": timeframe,
|
cmd_params = {"Symbol": symbol_name, "Timeframe": timeframe, "StartTime": start_time, "StopTime": stop_time}
|
||||||
"StartTime": start_time, "StopTime": stop_time}
|
return self.__send_command(self.__get_default_expert(), Mt5CommandType.Bars2, cmd_params)
|
||||||
return self.__send_command(
|
|
||||||
self.__get_default_expert(), Mt5CommandType.Bars2, cmd_params)
|
|
||||||
|
|
||||||
# BarsCalculated
|
# BarsCalculated
|
||||||
def bars_calculated(self, indicator_handle: int):
|
def bars_calculated(self, indicator_handle: int):
|
||||||
cmd_params = {"IndicatorHandle": indicator_handle}
|
cmd_params = {"IndicatorHandle": indicator_handle}
|
||||||
return self.__send_command(
|
return self.__send_command(self.__get_default_expert(), Mt5CommandType.BarsCalculated, cmd_params)
|
||||||
self.__get_default_expert(), Mt5CommandType.BarsCalculated, cmd_params)
|
|
||||||
|
|
||||||
# CopyBuffer
|
# CopyBuffer
|
||||||
def copy_buffer(self):
|
def copy_buffer(self):
|
||||||
@@ -281,58 +279,57 @@ class Mt5ApiClient:
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
# IndicatorCreate
|
# IndicatorCreate
|
||||||
def indicator_create(self, symbol: str, period: ENUM_TIMEFRAMES, indicator_type: ENUM_INDICATOR, parameters: list = []):
|
def indicator_create(
|
||||||
|
self, symbol: str, period: ENUM_TIMEFRAMES, indicator_type: ENUM_INDICATOR, parameters: list = []
|
||||||
|
):
|
||||||
cmd_params = {"Period": period, "IndicatorType": indicator_type}
|
cmd_params = {"Period": period, "IndicatorType": indicator_type}
|
||||||
if symbol is not None:
|
if symbol is not None:
|
||||||
cmd_params["Symbol"] = symbol
|
cmd_params["Symbol"] = symbol
|
||||||
if len(parameters) != 0:
|
if len(parameters) != 0:
|
||||||
cmd_params["Parameters"] = parameters
|
cmd_params["Parameters"] = parameters
|
||||||
return self.__send_command(
|
return self.__send_command(self.__get_default_expert(), Mt5CommandType.IndicatorCreate, cmd_params)
|
||||||
self.__get_default_expert(), Mt5CommandType.IndicatorCreate, cmd_params)
|
|
||||||
|
|
||||||
# IndicatorRelease
|
# IndicatorRelease
|
||||||
def indicator_release(self, indicator_handle: int):
|
def indicator_release(self, indicator_handle: int):
|
||||||
cmd_params = {"IndicatorHandle": indicator_handle}
|
cmd_params = {"IndicatorHandle": indicator_handle}
|
||||||
return self.__send_command(
|
return self.__send_command(self.__get_default_expert(), Mt5CommandType.IndicatorRelease, cmd_params)
|
||||||
self.__get_default_expert(), Mt5CommandType.IndicatorRelease, cmd_params)
|
|
||||||
|
|
||||||
# Market Info
|
# Market Info
|
||||||
|
|
||||||
# SymbolsTotal
|
# SymbolsTotal
|
||||||
def symbols_total(self, selected: bool):
|
def symbols_total(self, selected: bool):
|
||||||
cmd_params = {"Selected": selected}
|
cmd_params = {"Selected": selected}
|
||||||
return self.__send_command(
|
return self.__send_command(self.__get_default_expert(), Mt5CommandType.SymbolsTotal, cmd_params)
|
||||||
self.__get_default_expert(), Mt5CommandType.SymbolsTotal, cmd_params)
|
|
||||||
|
|
||||||
# SymbolName
|
# SymbolName
|
||||||
def symbol_name(self, pos: int, selected: bool):
|
def symbol_name(self, pos: int, selected: bool):
|
||||||
cmd_params = {"Pos": pos, "Selected" : selected}
|
cmd_params = {"Pos": pos, "Selected": selected}
|
||||||
return self.__send_command(
|
return self.__send_command(self.__get_default_expert(), Mt5CommandType.SymbolName, cmd_params)
|
||||||
self.__get_default_expert(), Mt5CommandType.SymbolName, cmd_params)
|
|
||||||
|
|
||||||
# SymbolSelect
|
# SymbolSelect
|
||||||
def symbol_select(self, symbol_name: str, selected: bool):
|
def symbol_select(self, symbol_name: str, selected: bool):
|
||||||
cmd_params = {"Symbol": symbol_name, "Selected": selected}
|
cmd_params = {"Symbol": symbol_name, "Selected": selected}
|
||||||
return self.__send_command(
|
return self.__send_command(self.__get_default_expert(), Mt5CommandType.SymbolSelect, cmd_params)
|
||||||
self.__get_default_expert(), Mt5CommandType.SymbolSelect, cmd_params)
|
|
||||||
|
|
||||||
# SymbolIsSynchronized
|
# SymbolIsSynchronized
|
||||||
def symbol_is_synchronized(self, symbol_name: str):
|
def symbol_is_synchronized(self, symbol_name: str):
|
||||||
cmd_params = {"Symbol": symbol_name}
|
cmd_params = {"Symbol": symbol_name}
|
||||||
return self.__send_command(
|
return self.__send_command(self.__get_default_expert(), Mt5CommandType.SymbolIsSynchronized, cmd_params)
|
||||||
self.__get_default_expert(), Mt5CommandType.SymbolIsSynchronized, cmd_params)
|
|
||||||
|
|
||||||
# SymbolInfoDouble
|
# SymbolInfoDouble
|
||||||
def symbol_info_double(self, symbol_name: str, prop_id: ENUM_SYMBOL_INFO_DOUBLE):
|
def symbol_info_double(self, symbol_name: str, prop_id: ENUM_SYMBOL_INFO_DOUBLE):
|
||||||
cmd_params = {"Symbol": symbol_name, "PropId": prop_id}
|
cmd_params = {"Symbol": symbol_name, "PropId": prop_id}
|
||||||
return self.__send_command(
|
return self.__send_command(self.__get_default_expert(), Mt5CommandType.SymbolInfoDouble, cmd_params)
|
||||||
self.__get_default_expert(), Mt5CommandType.SymbolInfoDouble, cmd_params)
|
|
||||||
|
|
||||||
# SymbolInfoInteger
|
# SymbolInfoInteger
|
||||||
def symbol_info_integer(self, symbol_name: str, prop_id: ENUM_SYMBOL_INFO_INTEGER):
|
def symbol_info_integer(self, symbol_name: str, prop_id: ENUM_SYMBOL_INFO_INTEGER):
|
||||||
cmd_params = {"Symbol": symbol_name, "PropId": prop_id}
|
cmd_params = {"Symbol": symbol_name, "PropId": prop_id}
|
||||||
return self.__send_command(
|
return self.__send_command(self.__get_default_expert(), Mt5CommandType.SymbolInfoInteger, cmd_params)
|
||||||
self.__get_default_expert(), Mt5CommandType.SymbolInfoInteger, cmd_params)
|
|
||||||
|
# SymbolInfoString
|
||||||
|
def symbol_info_string(self, symbol_name: str, prop_id: ENUM_SYMBOL_INFO_STRING):
|
||||||
|
cmd_params = {"Symbol": symbol_name, "PropId": prop_id}
|
||||||
|
return self.__send_command(self.__get_default_expert(), Mt5CommandType.SymbolInfoString, cmd_params)
|
||||||
|
|
||||||
# Private methods
|
# Private methods
|
||||||
|
|
||||||
@@ -355,18 +352,15 @@ class Mt5ApiClient:
|
|||||||
|
|
||||||
def __send_command(self, expert_handle, command_type, payload=None):
|
def __send_command(self, expert_handle, command_type, payload=None):
|
||||||
payload_json = None if payload is None else json.dumps(payload)
|
payload_json = None if payload is None else json.dumps(payload)
|
||||||
response = self.__rpcclient.send_command(
|
response = self.__rpcclient.send_command(expert_handle, command_type, payload_json)
|
||||||
expert_handle, command_type, payload_json)
|
|
||||||
if response is None:
|
if response is None:
|
||||||
self.__logger.warning("Failed to send commad. Result is None")
|
self.__logger.warning("Failed to send commad. Result is None")
|
||||||
raise Exception("Failed to send commad. Result is None")
|
raise Exception("Failed to send commad. Result is None")
|
||||||
response_json = json.loads(response)
|
response_json = json.loads(response)
|
||||||
error_code = int(response_json["ErrorCode"])
|
error_code = int(response_json["ErrorCode"])
|
||||||
if error_code != 0:
|
if error_code != 0:
|
||||||
self.__logger.warning(
|
self.__logger.warning(f"send_command: ErrorCode = {response.ErrorCode}. {response.ErrorMessage}")
|
||||||
f"send_command: ErrorCode = {response.ErrorCode}. {response.ErrorMessage}")
|
raise Exception(f"Failed to send command: ErrorCode = {response.ErrorCode}. {response.ErrorMessage} ")
|
||||||
raise Exception(
|
|
||||||
f"Failed to send command: ErrorCode = {response.ErrorCode}. {response.ErrorMessage} ")
|
|
||||||
return response_json["Value"]
|
return response_json["Value"]
|
||||||
|
|
||||||
def __process_tick_event(self, payload):
|
def __process_tick_event(self, payload):
|
||||||
@@ -423,40 +417,31 @@ class Mt5ApiClient:
|
|||||||
|
|
||||||
def __process_on_lock_tick(self, expert_handle, payload):
|
def __process_on_lock_tick(self, expert_handle, payload):
|
||||||
# TODO: must be implemented
|
# TODO: must be implemented
|
||||||
self.__logger.warning(
|
self.__logger.warning(f"event type OnLockTicks is not supported. {expert_handle} - {payload}")
|
||||||
f"event type OnLockTicks is not supported. {expert_handle} - {payload}")
|
|
||||||
|
|
||||||
def __process_on_trade_transaction(self, expert_handle, payload):
|
def __process_on_trade_transaction(self, expert_handle, payload):
|
||||||
trade_transaction_json = json.loads(payload)
|
trade_transaction_json = json.loads(payload)
|
||||||
trade_transaction = MqlTradeTransaction(
|
trade_transaction = MqlTradeTransaction(trade_transaction_json["Trans"])
|
||||||
trade_transaction_json["Trans"])
|
|
||||||
trade_request = MqlTradeRequest(trade_transaction_json["Request"])
|
trade_request = MqlTradeRequest(trade_transaction_json["Request"])
|
||||||
trade_result = MqlTradeResult(trade_transaction_json["Result"])
|
trade_result = MqlTradeResult(trade_transaction_json["Result"])
|
||||||
if self.__callback is not None:
|
if self.__callback is not None:
|
||||||
self.__callback.on_trade_transaction(
|
self.__callback.on_trade_transaction(expert_handle, trade_transaction, trade_request, trade_result)
|
||||||
expert_handle, trade_transaction, trade_request, trade_result)
|
|
||||||
|
|
||||||
# RPC event handlers
|
# RPC event handlers
|
||||||
|
|
||||||
def mt_rpc_on_event(self, expert_handle, event_type, payload):
|
def mt_rpc_on_event(self, expert_handle, event_type, payload):
|
||||||
self.__logger.debug(
|
self.__logger.debug(f"received event from {expert_handle}: {event_type}, {payload}")
|
||||||
f"received event from {expert_handle}: {event_type}, {payload}")
|
|
||||||
mt_event_type = Mt5EventType(int(event_type))
|
mt_event_type = Mt5EventType(int(event_type))
|
||||||
if mt_event_type == Mt5EventType.OnTick:
|
if mt_event_type == Mt5EventType.OnTick:
|
||||||
self.__event_loop.call_soon_threadsafe(
|
self.__event_loop.call_soon_threadsafe(self.__process_tick_event, payload)
|
||||||
self.__process_tick_event, payload)
|
|
||||||
elif mt_event_type == Mt5EventType.OnBookEvent:
|
elif mt_event_type == Mt5EventType.OnBookEvent:
|
||||||
self.__event_loop.call_soon_threadsafe(
|
self.__event_loop.call_soon_threadsafe(self.__process_on_book_event, expert_handle, payload)
|
||||||
self.__process_on_book_event, expert_handle, payload)
|
|
||||||
elif mt_event_type == Mt5EventType.OnLastTimeBar:
|
elif mt_event_type == Mt5EventType.OnLastTimeBar:
|
||||||
self.__event_loop.call_soon_threadsafe(
|
self.__event_loop.call_soon_threadsafe(self.__process_on_last_time_bar, expert_handle, payload)
|
||||||
self.__process_on_last_time_bar, expert_handle, payload)
|
|
||||||
elif mt_event_type == Mt5EventType.OnLockTicks:
|
elif mt_event_type == Mt5EventType.OnLockTicks:
|
||||||
self.__event_loop.call_soon_threadsafe(
|
self.__event_loop.call_soon_threadsafe(self.__process_on_lock_tick, expert_handle, payload)
|
||||||
self.__process_on_lock_tick, expert_handle, payload)
|
|
||||||
elif mt_event_type == Mt5EventType.OnTradeTransaction:
|
elif mt_event_type == Mt5EventType.OnTradeTransaction:
|
||||||
self.__event_loop.call_soon_threadsafe(
|
self.__event_loop.call_soon_threadsafe(self.__process_on_trade_transaction, expert_handle, payload)
|
||||||
self.__process_on_trade_transaction, expert_handle, payload)
|
|
||||||
else:
|
else:
|
||||||
self.__logger.warning(f"received unsupported event {event_type}")
|
self.__logger.warning(f"received unsupported event {event_type}")
|
||||||
|
|
||||||
@@ -466,15 +451,12 @@ class Mt5ApiClient:
|
|||||||
|
|
||||||
def mt_rpc_on_connection_failed(self, error_msg=None):
|
def mt_rpc_on_connection_failed(self, error_msg=None):
|
||||||
self.__logger.info(f"connection failed: {error_msg}")
|
self.__logger.info(f"connection failed: {error_msg}")
|
||||||
self.__event_loop.call_soon_threadsafe(
|
self.__event_loop.call_soon_threadsafe(self.__process_event_disconnect, error_msg)
|
||||||
self.__process_event_disconnect, error_msg)
|
|
||||||
|
|
||||||
def mt_rpc_on_expert_added(self, expert_handle):
|
def mt_rpc_on_expert_added(self, expert_handle):
|
||||||
self.__logger.info(f"expert added: {expert_handle}")
|
self.__logger.info(f"expert added: {expert_handle}")
|
||||||
self.__event_loop.call_soon_threadsafe(
|
self.__event_loop.call_soon_threadsafe(self.__process_expert_added, expert_handle)
|
||||||
self.__process_expert_added, expert_handle)
|
|
||||||
|
|
||||||
def mt_rpc_on_expert_removed(self, expert_handle):
|
def mt_rpc_on_expert_removed(self, expert_handle):
|
||||||
self.__logger.info(f"expert removed: {expert_handle}")
|
self.__logger.info(f"expert removed: {expert_handle}")
|
||||||
self.__event_loop.call_soon_threadsafe(
|
self.__event_loop.call_soon_threadsafe(self.__process_expert_removed, expert_handle)
|
||||||
self.__process_expert_removed, expert_handle)
|
|
||||||
|
|||||||
+474
-433
File diff suppressed because it is too large
Load Diff
+16
-13
@@ -9,6 +9,7 @@ from websockets.sync.client import connect as ws_connect
|
|||||||
class MtNotification(IntEnum):
|
class MtNotification(IntEnum):
|
||||||
ClientReady = 0
|
ClientReady = 0
|
||||||
|
|
||||||
|
|
||||||
class MtMessageType(IntEnum):
|
class MtMessageType(IntEnum):
|
||||||
Command = 0
|
Command = 0
|
||||||
Response = 1
|
Response = 1
|
||||||
@@ -18,6 +19,7 @@ class MtMessageType(IntEnum):
|
|||||||
ExpertRemoved = 5
|
ExpertRemoved = 5
|
||||||
Notification = 6
|
Notification = 6
|
||||||
|
|
||||||
|
|
||||||
class CommandTask:
|
class CommandTask:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.locker = Lock()
|
self.locker = Lock()
|
||||||
@@ -36,6 +38,7 @@ class CommandTask:
|
|||||||
with self.waiter:
|
with self.waiter:
|
||||||
self.waiter.notify()
|
self.waiter.notify()
|
||||||
|
|
||||||
|
|
||||||
class MtRpcClient:
|
class MtRpcClient:
|
||||||
def __init__(self, callback=None):
|
def __init__(self, callback=None):
|
||||||
self.__logger = logging.getLogger(__name__)
|
self.__logger = logging.getLogger(__name__)
|
||||||
@@ -47,8 +50,8 @@ class MtRpcClient:
|
|||||||
|
|
||||||
def connect(self, url):
|
def connect(self, url):
|
||||||
self.__logger.debug(f"connecting to {url}")
|
self.__logger.debug(f"connecting to {url}")
|
||||||
self.__ws = ws_connect(url);
|
self.__ws = ws_connect(url)
|
||||||
self.__receive_thread = Thread(target = self.__receive_messages_thread)
|
self.__receive_thread = Thread(target=self.__receive_messages_thread)
|
||||||
self.__receive_thread.start()
|
self.__receive_thread.start()
|
||||||
|
|
||||||
def disconnect(self):
|
def disconnect(self):
|
||||||
@@ -66,7 +69,7 @@ class MtRpcClient:
|
|||||||
self.__notification_tasks.pop(MtNotification.ClientReady)
|
self.__notification_tasks.pop(MtNotification.ClientReady)
|
||||||
return response
|
return response
|
||||||
|
|
||||||
def send_command(self, expert_handle, command_type, payload = None):
|
def send_command(self, expert_handle, command_type, payload=None):
|
||||||
command_id = self.__next_command_id
|
command_id = self.__next_command_id
|
||||||
self.__next_command_id += 1
|
self.__next_command_id += 1
|
||||||
task = CommandTask()
|
task = CommandTask()
|
||||||
@@ -82,9 +85,9 @@ class MtRpcClient:
|
|||||||
|
|
||||||
def __process_message(self, message):
|
def __process_message(self, message):
|
||||||
self.__logger.debug(f"process_message: {message}")
|
self.__logger.debug(f"process_message: {message}")
|
||||||
pieces = message.split(';', 1)
|
pieces = message.split(";", 1)
|
||||||
if len(pieces) != 2 or not pieces[0] or not pieces[1]:
|
if len(pieces) != 2 or not pieces[0] or not pieces[1]:
|
||||||
self.__logger.warning("process_message: Invalid message format");
|
self.__logger.warning("process_message: Invalid message format")
|
||||||
return
|
return
|
||||||
message_type = MtMessageType(int(pieces[0]))
|
message_type = MtMessageType(int(pieces[0]))
|
||||||
if message_type == MtMessageType.ExpertList:
|
if message_type == MtMessageType.ExpertList:
|
||||||
@@ -101,7 +104,7 @@ class MtRpcClient:
|
|||||||
self.__logger.warning(f"received unknown message type: {message_type}")
|
self.__logger.warning(f"received unknown message type: {message_type}")
|
||||||
|
|
||||||
def __process_expert_list(self, payload):
|
def __process_expert_list(self, payload):
|
||||||
pieces = payload.split(',')
|
pieces = payload.split(",")
|
||||||
experts = list()
|
experts = list()
|
||||||
for p in pieces:
|
for p in pieces:
|
||||||
experts.append(int(p))
|
experts.append(int(p))
|
||||||
@@ -111,17 +114,17 @@ class MtRpcClient:
|
|||||||
task.set_response(experts)
|
task.set_response(experts)
|
||||||
|
|
||||||
def __process_event(self, payload):
|
def __process_event(self, payload):
|
||||||
pieces = payload.split(';', 2)
|
pieces = payload.split(";", 2)
|
||||||
if len(pieces) != 3 or not pieces[0] or not pieces[1] or not pieces[2]:
|
if len(pieces) != 3 or not pieces[0] or not pieces[1] or not pieces[2]:
|
||||||
self.__logger.warning("process_event: Invalid message format");
|
self.__logger.warning("process_event: Invalid message format")
|
||||||
return
|
return
|
||||||
if self.__callback is not None:
|
if self.__callback is not None:
|
||||||
self.__callback.mt_rpc_on_event(int(pieces[0]), int(pieces[1]), pieces[2])
|
self.__callback.mt_rpc_on_event(int(pieces[0]), int(pieces[1]), pieces[2])
|
||||||
|
|
||||||
def __process_response(self, payload):
|
def __process_response(self, payload):
|
||||||
pieces = payload.split(';', 2)
|
pieces = payload.split(";", 2)
|
||||||
if len(pieces) != 3 or not pieces[0] or not pieces[1] or not pieces[2]:
|
if len(pieces) != 3 or not pieces[0] or not pieces[1] or not pieces[2]:
|
||||||
self.__logger.warning("process_response: Invalid message format");
|
self.__logger.warning("process_response: Invalid message format")
|
||||||
return
|
return
|
||||||
command_id = int(pieces[1])
|
command_id = int(pieces[1])
|
||||||
with self.__lock:
|
with self.__lock:
|
||||||
@@ -159,6 +162,6 @@ class MtRpcClient:
|
|||||||
return f"{int(MtMessageType.Notification)};{notification_type}"
|
return f"{int(MtMessageType.Notification)};{notification_type}"
|
||||||
|
|
||||||
def __create_mt_command(self, expert_handle, command_id, command_type, payload):
|
def __create_mt_command(self, expert_handle, command_id, command_type, payload):
|
||||||
if (payload is None):
|
if payload is None:
|
||||||
return f"{MtMessageType.Command};{expert_handle};{command_id};{command_type}";
|
return f"{MtMessageType.Command};{expert_handle};{command_id};{command_type}"
|
||||||
return f"{MtMessageType.Command};{expert_handle};{command_id};{command_type};{payload}";
|
return f"{MtMessageType.Command};{expert_handle};{command_id};{command_type};{payload}"
|
||||||
|
|||||||
Reference in New Issue
Block a user