PyMtApi5: implemented function SymbolInfoString; formatted code.

This commit is contained in:
Vyacheslav Demidyuk
2025-01-18 00:32:44 +02:00
parent 150995baea
commit 33bff44b39
4 changed files with 563 additions and 526 deletions
+11
View File
@@ -38,6 +38,7 @@ class Mt5ApiApp:
"SymbolIsSynchronized": self.process_symbol_is_synchronized,
"SymbolInfoDouble": self.process_symbol_info_double,
"SymbolInfoInteger": self.process_symbol_info_integer,
"SymbolInfoString": self.process_symbol_info_string,
}
def on_disconnect(self, error_msg=None):
@@ -204,6 +205,16 @@ class Mt5ApiApp:
result = mtapi.symbol_info_integer(symbol, prop_id)
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):
while mtapi.is_connected():
filename = "client.cmd"
+56 -74
View File
@@ -1,11 +1,12 @@
import asyncio
import json
import logging
import asyncio
from mt5enums import *
from enum import IntEnum
from threading import Lock, Thread
from mtrpcclient import MtRpcClient
from mt5commandtype import Mt5CommandType
from mt5enums import *
from mtrpcclient import MtRpcClient
class Mt5EventType(IntEnum):
@@ -63,10 +64,12 @@ class MqlTradeTransaction:
self.time_expiration = mql_trade_transaction_json["MtTimeExpiration"]
def __repr__(self):
return (f"deal = {self.deal}, order = {self.order}, symbol = {self.symbol}, transaction_type = {self.transaction_type}, "
return (
f"deal = {self.deal}, order = {self.order}, symbol = {self.symbol}, transaction_type = {self.transaction_type}, "
f"order_type = {self.order_type}, order_state = {self.order_state}, deal_type = {self.deal_type}, time_type = {self.time_type}, "
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}")
f"position = {self.position}, position_by = {self.position_by}, time_expiration = {self.time_expiration}"
)
class MqlTradeRequest:
@@ -90,10 +93,12 @@ class MqlTradeRequest:
# self.position_by = mql_trade_request_json["PositionBy"]
def __repr__(self):
return (f"action = {self.action}, magic = {self.magic}, order = {self.order}, symbol = {self.symbol}, volume = {self.volume}, "
return (
f"action = {self.action}, magic = {self.magic}, order = {self.order}, symbol = {self.symbol}, volume = {self.volume}, "
f"price = {self.price}, stop_limit = {self.stop_limit}, sl = {self.sl}, tp = {self.tp}, deviation = {self.deviation}, "
f"order_type = {self.order_type}, type_filling = {self.type_filling}, type_time = {self.type_time}, expiration = {self.expiration}, "
f"comment = {self.comment}")
f"comment = {self.comment}"
)
class MqlTradeResult:
@@ -109,8 +114,10 @@ class MqlTradeResult:
self.request_id = mql_trade_result_json["Request_id"]
def __repr__(self):
return (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}")
return (
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:
@@ -176,20 +183,17 @@ class Mt5ApiClient:
# AccountInfoDouble
def account_info_double(self, property_id: ENUM_ACCOUNT_INFO_DOUBLE):
cmd_params = {"PropertyId": property_id}
return self.__send_command(
self.__get_default_expert(), Mt5CommandType.AccountInfoDouble, cmd_params)
return self.__send_command(self.__get_default_expert(), Mt5CommandType.AccountInfoDouble, cmd_params)
# AccountInfoInteger
def account_info_integer(self, property_id: ENUM_ACCOUNT_INFO_INTEGER):
cmd_params = {"PropertyId": property_id}
return self.__send_command(
self.__get_default_expert(), Mt5CommandType.AccountInfoInteger, cmd_params)
return self.__send_command(self.__get_default_expert(), Mt5CommandType.AccountInfoInteger, cmd_params)
# AccountInfoString
def account_info_string(self, property_id: ENUM_ACCOUNT_INFO_STRING):
cmd_params = {"PropertyId": property_id}
return self.__send_command(
self.__get_default_expert(), Mt5CommandType.AccountInfoString, cmd_params)
return self.__send_command(self.__get_default_expert(), Mt5CommandType.AccountInfoString, cmd_params)
# 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):
if symbol_name is None:
symbol_name = ""
cmd_params = {"Symbol": symbol_name,
"Timeframe": timeframe, "PropId": prop_id}
return self.__send_command(
self.__get_default_expert(), Mt5CommandType.SeriesInfoInteger, cmd_params)
cmd_params = {"Symbol": symbol_name, "Timeframe": timeframe, "PropId": prop_id}
return self.__send_command(self.__get_default_expert(), Mt5CommandType.SeriesInfoInteger, cmd_params)
# Bars
def bars(self, symbol_name, timeframe: ENUM_TIMEFRAMES):
if symbol_name is None:
symbol_name = ""
cmd_params = {"Symbol": symbol_name, "Timeframe": timeframe}
return self.__send_command(
self.__get_default_expert(), Mt5CommandType.Bars, cmd_params)
return self.__send_command(self.__get_default_expert(), Mt5CommandType.Bars, cmd_params)
# Bars (for a specified period)
def bars_period(self, symbol_name, timeframe: ENUM_TIMEFRAMES, start_time: int, stop_time: int):
if symbol_name is None:
symbol_name = ""
cmd_params = {"Symbol": symbol_name, "Timeframe": timeframe,
"StartTime": start_time, "StopTime": stop_time}
return self.__send_command(
self.__get_default_expert(), Mt5CommandType.Bars2, cmd_params)
cmd_params = {"Symbol": symbol_name, "Timeframe": timeframe, "StartTime": start_time, "StopTime": stop_time}
return self.__send_command(self.__get_default_expert(), Mt5CommandType.Bars2, cmd_params)
# BarsCalculated
def bars_calculated(self, indicator_handle: int):
cmd_params = {"IndicatorHandle": indicator_handle}
return self.__send_command(
self.__get_default_expert(), Mt5CommandType.BarsCalculated, cmd_params)
return self.__send_command(self.__get_default_expert(), Mt5CommandType.BarsCalculated, cmd_params)
# CopyBuffer
def copy_buffer(self):
@@ -281,58 +279,57 @@ class Mt5ApiClient:
pass
# 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}
if symbol is not None:
cmd_params["Symbol"] = symbol
if len(parameters) != 0:
cmd_params["Parameters"] = parameters
return self.__send_command(
self.__get_default_expert(), Mt5CommandType.IndicatorCreate, cmd_params)
return self.__send_command(self.__get_default_expert(), Mt5CommandType.IndicatorCreate, cmd_params)
# IndicatorRelease
def indicator_release(self, indicator_handle: int):
cmd_params = {"IndicatorHandle": indicator_handle}
return self.__send_command(
self.__get_default_expert(), Mt5CommandType.IndicatorRelease, cmd_params)
return self.__send_command(self.__get_default_expert(), Mt5CommandType.IndicatorRelease, cmd_params)
# Market Info
# SymbolsTotal
def symbols_total(self, selected: bool):
cmd_params = {"Selected": selected}
return self.__send_command(
self.__get_default_expert(), Mt5CommandType.SymbolsTotal, cmd_params)
return self.__send_command(self.__get_default_expert(), Mt5CommandType.SymbolsTotal, cmd_params)
# SymbolName
def symbol_name(self, pos: int, selected: bool):
cmd_params = {"Pos": pos, "Selected": selected}
return self.__send_command(
self.__get_default_expert(), Mt5CommandType.SymbolName, cmd_params)
return self.__send_command(self.__get_default_expert(), Mt5CommandType.SymbolName, cmd_params)
# SymbolSelect
def symbol_select(self, symbol_name: str, selected: bool):
cmd_params = {"Symbol": symbol_name, "Selected": selected}
return self.__send_command(
self.__get_default_expert(), Mt5CommandType.SymbolSelect, cmd_params)
return self.__send_command(self.__get_default_expert(), Mt5CommandType.SymbolSelect, cmd_params)
# SymbolIsSynchronized
def symbol_is_synchronized(self, symbol_name: str):
cmd_params = {"Symbol": symbol_name}
return self.__send_command(
self.__get_default_expert(), Mt5CommandType.SymbolIsSynchronized, cmd_params)
return self.__send_command(self.__get_default_expert(), Mt5CommandType.SymbolIsSynchronized, cmd_params)
# SymbolInfoDouble
def symbol_info_double(self, symbol_name: str, prop_id: ENUM_SYMBOL_INFO_DOUBLE):
cmd_params = {"Symbol": symbol_name, "PropId": prop_id}
return self.__send_command(
self.__get_default_expert(), Mt5CommandType.SymbolInfoDouble, cmd_params)
return self.__send_command(self.__get_default_expert(), Mt5CommandType.SymbolInfoDouble, cmd_params)
# SymbolInfoInteger
def symbol_info_integer(self, symbol_name: str, prop_id: ENUM_SYMBOL_INFO_INTEGER):
cmd_params = {"Symbol": symbol_name, "PropId": prop_id}
return self.__send_command(
self.__get_default_expert(), Mt5CommandType.SymbolInfoInteger, cmd_params)
return self.__send_command(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
@@ -355,18 +352,15 @@ class Mt5ApiClient:
def __send_command(self, expert_handle, command_type, payload=None):
payload_json = None if payload is None else json.dumps(payload)
response = self.__rpcclient.send_command(
expert_handle, command_type, payload_json)
response = self.__rpcclient.send_command(expert_handle, command_type, payload_json)
if response is None:
self.__logger.warning("Failed to send commad. Result is None")
raise Exception("Failed to send commad. Result is None")
response_json = json.loads(response)
error_code = int(response_json["ErrorCode"])
if error_code != 0:
self.__logger.warning(
f"send_command: ErrorCode = {response.ErrorCode}. {response.ErrorMessage}")
raise Exception(
f"Failed to send command: ErrorCode = {response.ErrorCode}. {response.ErrorMessage} ")
self.__logger.warning(f"send_command: ErrorCode = {response.ErrorCode}. {response.ErrorMessage}")
raise Exception(f"Failed to send command: ErrorCode = {response.ErrorCode}. {response.ErrorMessage} ")
return response_json["Value"]
def __process_tick_event(self, payload):
@@ -423,40 +417,31 @@ class Mt5ApiClient:
def __process_on_lock_tick(self, expert_handle, payload):
# TODO: must be implemented
self.__logger.warning(
f"event type OnLockTicks is not supported. {expert_handle} - {payload}")
self.__logger.warning(f"event type OnLockTicks is not supported. {expert_handle} - {payload}")
def __process_on_trade_transaction(self, expert_handle, payload):
trade_transaction_json = json.loads(payload)
trade_transaction = MqlTradeTransaction(
trade_transaction_json["Trans"])
trade_transaction = MqlTradeTransaction(trade_transaction_json["Trans"])
trade_request = MqlTradeRequest(trade_transaction_json["Request"])
trade_result = MqlTradeResult(trade_transaction_json["Result"])
if self.__callback is not None:
self.__callback.on_trade_transaction(
expert_handle, trade_transaction, trade_request, trade_result)
self.__callback.on_trade_transaction(expert_handle, trade_transaction, trade_request, trade_result)
# RPC event handlers
def mt_rpc_on_event(self, expert_handle, event_type, payload):
self.__logger.debug(
f"received event from {expert_handle}: {event_type}, {payload}")
self.__logger.debug(f"received event from {expert_handle}: {event_type}, {payload}")
mt_event_type = Mt5EventType(int(event_type))
if mt_event_type == Mt5EventType.OnTick:
self.__event_loop.call_soon_threadsafe(
self.__process_tick_event, payload)
self.__event_loop.call_soon_threadsafe(self.__process_tick_event, payload)
elif mt_event_type == Mt5EventType.OnBookEvent:
self.__event_loop.call_soon_threadsafe(
self.__process_on_book_event, expert_handle, payload)
self.__event_loop.call_soon_threadsafe(self.__process_on_book_event, expert_handle, payload)
elif mt_event_type == Mt5EventType.OnLastTimeBar:
self.__event_loop.call_soon_threadsafe(
self.__process_on_last_time_bar, expert_handle, payload)
self.__event_loop.call_soon_threadsafe(self.__process_on_last_time_bar, expert_handle, payload)
elif mt_event_type == Mt5EventType.OnLockTicks:
self.__event_loop.call_soon_threadsafe(
self.__process_on_lock_tick, expert_handle, payload)
self.__event_loop.call_soon_threadsafe(self.__process_on_lock_tick, expert_handle, payload)
elif mt_event_type == Mt5EventType.OnTradeTransaction:
self.__event_loop.call_soon_threadsafe(
self.__process_on_trade_transaction, expert_handle, payload)
self.__event_loop.call_soon_threadsafe(self.__process_on_trade_transaction, expert_handle, payload)
else:
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):
self.__logger.info(f"connection failed: {error_msg}")
self.__event_loop.call_soon_threadsafe(
self.__process_event_disconnect, error_msg)
self.__event_loop.call_soon_threadsafe(self.__process_event_disconnect, error_msg)
def mt_rpc_on_expert_added(self, expert_handle):
self.__logger.info(f"expert added: {expert_handle}")
self.__event_loop.call_soon_threadsafe(
self.__process_expert_added, expert_handle)
self.__event_loop.call_soon_threadsafe(self.__process_expert_added, expert_handle)
def mt_rpc_on_expert_removed(self, expert_handle):
self.__logger.info(f"expert removed: {expert_handle}")
self.__event_loop.call_soon_threadsafe(
self.__process_expert_removed, expert_handle)
self.__event_loop.call_soon_threadsafe(self.__process_expert_removed, expert_handle)
+53 -12
View File
@@ -2,6 +2,7 @@ from enum import IntEnum
# Chart Timeframes
class ENUM_TIMEFRAMES(IntEnum):
PERIOD_CURRENT = 0
PERIOD_M1 = 1
@@ -29,6 +30,7 @@ class ENUM_TIMEFRAMES(IntEnum):
# Charts Properties
class ENUM_CHART_PROPERTY_DOUBLE(IntEnum):
CHART_SHIFT_SIZE = 3
CHART_FIXED_POSITION = 41
@@ -113,6 +115,7 @@ class ENUM_CHART_POSITION(IntEnum):
# Client Terminal Properties
class ENUM_TERMINAL_INFO_INTEGER(IntEnum):
TERMINAL_BUILD = 5
TERMINAL_COMMUNITY_ACCOUNT = 23
@@ -153,6 +156,7 @@ class ENUM_TERMINAL_INFO_STRING(IntEnum):
# Symbol Properties
class ENUM_SYMBOL_INFO_INTEGER(IntEnum):
SYMBOL_CUSTOM = 78
SYMBOL_BACKGROUND_COLOR = 79
@@ -324,6 +328,7 @@ class ENUM_SYMBOL_OPTION_MODE(IntEnum):
# Account Properties
class ENUM_ACCOUNT_INFO_INTEGER(IntEnum):
ACCOUNT_LOGIN = 0 # Account number
ACCOUNT_TRADE_MODE = 32 # Account trade mode
@@ -379,17 +384,23 @@ class ENUM_ACCOUNT_MARGIN_MODE(IntEnum):
# Trade Constants:
# History Database Properties
class ENUM_SERIES_INFO_INTEGER(IntEnum):
SERIES_BARS_COUNT = 0 # Bars count for the symbol-period for the current moment
SERIES_FIRSTDATE = 1 # The very first date for the symbol-period for the current moment
SERIES_LASTBAR_DATE = 5 # Open time of the last bar of the symbol-period
SERIES_SERVER_FIRSTDATE = 2 # The very first date in the history of the symbol on the server regardless of the timeframe
SERIES_TERMINAL_FIRSTDATE = 3 # The very first date in the history of the symbol in the client terminal, regardless of the timeframe
SERIES_SERVER_FIRSTDATE = (
2 # The very first date in the history of the symbol on the server regardless of the timeframe
)
SERIES_TERMINAL_FIRSTDATE = (
3 # The very first date in the history of the symbol in the client terminal, regardless of the timeframe
)
SERIES_SYNCHRONIZED = 4 # S ymbol/period data synchronization flag for the current moment
# Order Properties
class ENUM_ORDER_PROPERTY_INTEGER(IntEnum):
ORDER_TICKET = 22 # Order ticket. Unique number assigned to each order
ORDER_TIME_SETUP = 1 # Order setup time
@@ -431,8 +442,12 @@ class ENUM_ORDER_TYPE(IntEnum):
ORDER_TYPE_SELL_LIMIT = 3 # Sell Limit pending order
ORDER_TYPE_BUY_STOP = 4 # Buy Stop pending order
ORDER_TYPE_SELL_STOP = 5 # Sell Stop pending order
ORDER_TYPE_BUY_STOP_LIMIT = 6 # Upon reaching the order price, a pending Buy Limit order is places at the StopLimit price
ORDER_TYPE_SELL_STOP_LIMIT = 7 # Upon reaching the order price, a pending Sell Limit order is places at the StopLimit price
ORDER_TYPE_BUY_STOP_LIMIT = (
6 # Upon reaching the order price, a pending Buy Limit order is places at the StopLimit price
)
ORDER_TYPE_SELL_STOP_LIMIT = (
7 # Upon reaching the order price, a pending Sell Limit order is places at the StopLimit price
)
ORDER_TYPE_CLOSE_BY = 8 # Order to close a position by an opposite one
@@ -474,6 +489,7 @@ class ENUM_ORDER_REASON(IntEnum):
# Position Properties
class ENUM_POSITION_PROPERTY_INTEGER(IntEnum):
POSITION_TICKET = 17 # Position ticket
POSITION_TIME = 1 # Position open time
@@ -508,14 +524,23 @@ class ENUM_POSITION_TYPE(IntEnum):
class ENUM_POSITION_REASON(IntEnum):
POSITION_REASON_CLIENT = 0 # The position was opened as a result of activation of an order placed from a desktop terminal
POSITION_REASON_MOBILE = 1 # The position was opened as a result of activation of an order placed from a mobile application
POSITION_REASON_WEB = 2 # The position was opened as a result of activation of an order placed from the web platform
POSITION_REASON_EXPERT = 3 # The position was opened as a result of activation of an order placed from an MQL5 program
POSITION_REASON_CLIENT = (
0 # The position was opened as a result of activation of an order placed from a desktop terminal
)
POSITION_REASON_MOBILE = (
1 # The position was opened as a result of activation of an order placed from a mobile application
)
POSITION_REASON_WEB = (
2 # The position was opened as a result of activation of an order placed from the web platform
)
POSITION_REASON_EXPERT = (
3 # The position was opened as a result of activation of an order placed from an MQL5 program
)
# Deal Properties
class ENUM_DEAL_PROPERTY_INTEGER(IntEnum):
DEAL_TICKET = 15 # Deal ticket. Unique number assigned to each deal
DEAL_ORDER = 1 # Deal order number
@@ -572,7 +597,9 @@ class ENUM_DEAL_ENTRY(IntEnum):
class ENUM_DEAL_REASON(IntEnum):
DEAL_REASON_CLIENT = 0 # The deal was executed as a result of activation of an order placed from a desktop terminal
DEAL_REASON_MOBILE = 1 # The deal was executed as a result of activation of an order placed from a mobile application
DEAL_REASON_MOBILE = (
1 # The deal was executed as a result of activation of an order placed from a mobile application
)
DEAL_REASON_WEB = 2 # The deal was executed as a result of activation of an order placed from the web platform
DEAL_REASON_EXPERT = 3 # The deal was executed as a result of activation of an order placed from an MQL5 program, i.e. an Expert Advisor or a script
DEAL_REASON_SL = 4 # The deal was executed as a result of Stop Loss activation
@@ -585,6 +612,7 @@ class ENUM_DEAL_REASON(IntEnum):
# Trade Operation Types
class ENUM_TRADE_REQUEST_ACTIONS(IntEnum):
TRADE_ACTION_DEAL = 1 # Place a trade order for an immediate execution with the specified parameters (market order)
TRADE_ACTION_PENDING = 5 # Place a trade order for the execution under specified conditions (pending order)
@@ -596,15 +624,20 @@ class ENUM_TRADE_REQUEST_ACTIONS(IntEnum):
# Trade Transaction Types
class ENUM_TRADE_TRANSACTION_TYPE(IntEnum):
TRADE_TRANSACTION_ORDER_ADD = 0 # Adding a new open order
TRADE_TRANSACTION_ORDER_UPDATE = 1 # Updating an open order. The updates include not only evident changes from the client terminal
TRADE_TRANSACTION_ORDER_UPDATE = (
1 # Updating an open order. The updates include not only evident changes from the client terminal
)
# or a trade server sides but also changes of an order state when setting it
# (for example, transition from ORDER_STATE_STARTED to ORDER_STATE_PLACED or from ORDER_STATE_PLACED to ORDER_STATE_PARTIAL, etc.).
TRADE_TRANSACTION_ORDER_DELETE = 2 # Removing an order from the list of the open ones. An order can be deleted from the open ones as a result of setting an appropriate request
# or execution (filling) and moving to the history.
TRADE_TRANSACTION_DEAL_ADD = 6 # Adding a deal to the history. The action is performed as a result of an order execution or performing operations with an account balance.
TRADE_TRANSACTION_DEAL_UPDATE = 7 # Updating a deal in the history. There may be cases when a previously executed deal is changed on a server.
TRADE_TRANSACTION_DEAL_UPDATE = (
7 # Updating a deal in the history. There may be cases when a previously executed deal is changed on a server.
)
# For example, a deal has been changed in an external trading system (exchange) where it was previously transferred by a broker.
TRADE_TRANSACTION_DEAL_DELETE = 8 # Deleting a deal from the history. There may be cases when a previously executed deal is deleted from a server.
# For example, a deal has been deleted in an external trading system (exchange) where it was previously transferred by a broker.
@@ -621,6 +654,7 @@ class ENUM_TRADE_TRANSACTION_TYPE(IntEnum):
# Trade Orders in Depth Of Market
class ENUM_BOOK_TYPE(IntEnum):
BOOK_TYPE_SELL = 1 # Sell order (Offer)
BOOK_TYPE_BUY = 2 # Buy order (Bid)
@@ -630,6 +664,7 @@ class ENUM_BOOK_TYPE(IntEnum):
# Object Types
class ENUM_OBJECT(IntEnum):
OBJ_VLINE = 0 # Vertical Line
OBJ_HLINE = 1 # Horizontal Line
@@ -679,6 +714,7 @@ class ENUM_OBJECT(IntEnum):
# Object Properties
class ENUM_OBJECT_PROPERTY_DOUBLE(IntEnum):
OBJPROP_PRICE = 9 # Price coordinate
OBJPROP_LEVELVALUE = 204 # Level value
@@ -692,7 +728,9 @@ class ENUM_OBJECT_PROPERTY_INTEGER(IntEnum):
OBJPROP_STYLE = 1 # Style
OBJPROP_WIDTH = 2 # Line thickness
OBJPROP_BACK = 3 # Object in the background
OBJPROP_ZORDER = 207 # Priority of a graphical object for receiving events of clicking on a chart (CHARTEVENT_CLICK).
OBJPROP_ZORDER = (
207 # Priority of a graphical object for receiving events of clicking on a chart (CHARTEVENT_CLICK).
)
# The default zero value is set when creating an object; the priority can be increased if necessary.
# When objects are placed one atop another, only one of them with the highest priority will receive the CHARTEVENT_CLICK event.
OBJPROP_FILL = 1031 # Fill an object with color (for OBJ_RECTANGLE, OBJ_TRIANGLE, OBJ_ELLIPSE, OBJ_CHANNEL, OBJ_STDDEVCHANNEL, OBJ_REGRESSION)
@@ -765,6 +803,7 @@ class ENUM_ALIGN_MODE(IntEnum):
# Price Constants
class ENUM_APPLIED_PRICE(IntEnum):
PRICE_CLOSE = 1 # Close price
PRICE_OPEN = 2 # Open price
@@ -787,6 +826,7 @@ class ENUM_STO_PRICE(IntEnum):
# Smoothing Methods
class ENUM_MA_METHOD(IntEnum):
MODE_SMA = 0 # Simple averaging
MODE_EMA = 1 # Exponential averaging
@@ -796,6 +836,7 @@ class ENUM_MA_METHOD(IntEnum):
# Indicator constants
class ENUM_INDICATOR(IntEnum):
IND_AC = 5 # Accelerator Oscillator
IND_AD = 6 # Accumulation/Distribution
+14 -11
View File
@@ -9,6 +9,7 @@ from websockets.sync.client import connect as ws_connect
class MtNotification(IntEnum):
ClientReady = 0
class MtMessageType(IntEnum):
Command = 0
Response = 1
@@ -18,6 +19,7 @@ class MtMessageType(IntEnum):
ExpertRemoved = 5
Notification = 6
class CommandTask:
def __init__(self):
self.locker = Lock()
@@ -36,6 +38,7 @@ class CommandTask:
with self.waiter:
self.waiter.notify()
class MtRpcClient:
def __init__(self, callback=None):
self.__logger = logging.getLogger(__name__)
@@ -47,7 +50,7 @@ class MtRpcClient:
def connect(self, 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.start()
@@ -82,9 +85,9 @@ class MtRpcClient:
def __process_message(self, 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]:
self.__logger.warning("process_message: Invalid message format");
self.__logger.warning("process_message: Invalid message format")
return
message_type = MtMessageType(int(pieces[0]))
if message_type == MtMessageType.ExpertList:
@@ -101,7 +104,7 @@ class MtRpcClient:
self.__logger.warning(f"received unknown message type: {message_type}")
def __process_expert_list(self, payload):
pieces = payload.split(',')
pieces = payload.split(",")
experts = list()
for p in pieces:
experts.append(int(p))
@@ -111,17 +114,17 @@ class MtRpcClient:
task.set_response(experts)
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]:
self.__logger.warning("process_event: Invalid message format");
self.__logger.warning("process_event: Invalid message format")
return
if self.__callback is not None:
self.__callback.mt_rpc_on_event(int(pieces[0]), int(pieces[1]), pieces[2])
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]:
self.__logger.warning("process_response: Invalid message format");
self.__logger.warning("process_response: Invalid message format")
return
command_id = int(pieces[1])
with self.__lock:
@@ -159,6 +162,6 @@ class MtRpcClient:
return f"{int(MtMessageType.Notification)};{notification_type}"
def __create_mt_command(self, expert_handle, command_id, command_type, payload):
if (payload is None):
return f"{MtMessageType.Command};{expert_handle};{command_id};{command_type}";
return f"{MtMessageType.Command};{expert_handle};{command_id};{command_type};{payload}";
if payload is None:
return f"{MtMessageType.Command};{expert_handle};{command_id};{command_type}"
return f"{MtMessageType.Command};{expert_handle};{command_id};{command_type};{payload}"