import MetaTrader5 as mt5 import pandas as pd import numpy as np import math import argparse import configparser from envs.real_net_env import RealNetEnv, RealNetController from envs.functions import getState, formatPrice from agents.models import MA2C from utils import Predictor SYMBOL = "EURUSD" DEVIATION = 20 TIMEFRAME = mt5.TIMEFRAME_H4 VOLUME = 0.03 PERIOD = 11 def parse_args(): parser = argparse.ArgumentParser() parser.add_argument('--config-dir', type=str, required=False, default='config_ma2c_real.ini', help="inference config dir") parser.add_argument('--port', type=int, required=False, default=0, help="running port") parser.add_argument('--policy-type', type=str, required=False, default='default', help="inference policy type in evaluation: default, stochastic, or deterministic") parser.add_argument('--position-type', type=dict, required=False, default={'long': 1, 'short': -1}, help="types of position") args = parser.parse_args() return args def market_order(symbol, volume, order_type): tick = mt5.symbol_info_tick(symbol) order_dict = {'long': 0, 'short': 1} price_dict = {'long': tick.ask, 'short': tick.bid} request = { "action": mt5.TRADE_ACTION_DEAL, "symbol": symbol, "volume": volume, "type": order_dict[order_type], "price": price_dict[order_type], "deviation": DEVIATION, "magic": 100, "comment": "python market order", "type_time": mt5.ORDER_TIME_GTC, "type_filling": mt5.ORDER_FILLING_IOC, } order_result = mt5.order_send(request) print(order_result) return order_result # function to close an order base don ticket id def close_order(ticket): positions = mt5.positions_get() for pos in positions: tick = mt5.symbol_info_tick(pos.symbol) # 0 represents buy, 1 represents sell - inverting order_type to close the position type_dict = {0: 1, 1: 0} price_dict = {0: tick.ask, 1: tick.bid} if pos.ticket == ticket: request = { "action": mt5.TRADE_ACTION_DEAL, "position": pos.ticket, "symbol": pos.symbol, "volume": pos.volume, "type": type_dict[pos.type], "price": price_dict[pos.type], "deviation": DEVIATION, "magic": 100, "comment": "python close order", "type_time": mt5.ORDER_TIME_GTC, "type_filling": mt5.ORDER_FILLING_IOC, } order_result = mt5.order_send(request) print(order_result) return order_result return 'Ticket does not exist' def sigmoid(x): return 1 / (1 + math.exp(-x)) def _norm_clip_state(x, norm, clip=-1): x = x / norm return x if clip < 0 else np.clip(x, 0, clip) def getState(symbol, timeframe, period, index=1000): bars = mt5.copy_rates_from_pos(symbol, timeframe, 1, period) bars_df = pd.DataFrame(bars) vec = bars_df.close.tolist() vec = [x*index for x in vec] res = [] for i in range(period - 1): res.append(sigmoid(vec[i + 1] - vec[i])) return np.array(res) def init_env(config, port=1, naive_policy=False): if not naive_policy: return RealNetEnv(config, port=port) else: env = RealNetEnv(config, port=port) policy = RealNetController(env.node_names, env.nodes) return env, policy def data_preprocessing(cur_state, norm, clip, agents): # hard code the state ordering as wave, wait, fp state = [] # measure the most recent state norm_cur_state = _norm_clip_state(cur_state, norm, clip) # get the appropriate state vectors for _ in agents: # wave is required in state cur_state = [norm_cur_state] state.append(np.concatenate(cur_state)) return state def main(args): config_dir = args.config_dir port = args.port policy_type = args.policy_type agent_type = args.position_type # initialize start value inventory = {} open_ticket = {} for agent in [*agent_type]: inventory[agent] = [] open_ticket[agent] = [] total_profit = 0 balance_list = [] pre_state = np.array([]) # load config file for env config = configparser.ConfigParser() config.read(config_dir) cur_balance = config['ENV_CONFIG'].getint('balance') norm = config['ENV_CONFIG'].getfloat('norm_wave') clip = config['ENV_CONFIG'].getfloat('clip_wave') # init env env = init_env(config['ENV_CONFIG'], port) # load model for agent # init centralized or multi agent model = MA2C(env.n_s_ls, env.n_a_ls, env.n_w_ls, env.n_f_ls, 0, config['MODEL_CONFIG']) model.load('weights/') model.reset() # collect evaluation data predictor = Predictor(env, model, policy_type=policy_type) # init mt5 mt5.initialize() while True: cur_state = getState(symbol=SYMBOL, timeframe=TIMEFRAME, period=PERIOD) if not np.array_equal(cur_state, pre_state): state = data_preprocessing(cur_state, norm, clip, [*agent_type]) action = predictor.run(state) print('---ACTION--- :', action) tick = mt5.symbol_info_tick(SYMBOL) price_dict = {'long': tick.ask, 'short': tick.bid} for agent, a in zip([*agent_type], list(action)): if a == 1: market_order(SYMBOL, VOLUME, agent) inventory[agent].append(price_dict[agent]) open_ticket[agent].append(mt5.positions_get()[-1].ticket) elif a == 2 and len(inventory[agent]) > 0: close_order(open_ticket[agent].pop(0)) order_price = inventory[agent].pop(0) profit = (price_dict[agent] - order_price) * \ agent_type[agent] * VOLUME * 100000 total_profit += profit cur_balance += profit balance_list.append(round(cur_balance, 2)) print("--------------------------------") print("Total Profit: " + formatPrice(total_profit)) print('Curent Balance: ' + formatPrice(cur_balance)) print('Balance List', balance_list) print("--------------------------------") pre_state = cur_state if __name__ == '__main__': args = parse_args() main(args)