import os, time
import datetimeas dt
from json import loads, dump
from random import randint
import numpy as np
from Classes import date_time, Bar
import Functions
import MetaTrader5 as mt5
N = 1000 # количество отсчётов, сохраняемых в файлах котировок
n = 10
d = 0
N_sd_sell_max = 3 # максимальное количество сделок типа sell по одному инструменту
N_sd_buy_max = 3 # максимальное количество сделок типа buy по одному инструменту
volume = 0.01 # объём сделок
account_demo = ['Alpari-MT5-Demo', 51056680 , 'password']
work_account = account_demo
work_catalog = 'Z:\\fx_for_forum\\fx\\'
instruments = ['EURUSD', 'GBPUSD', 'EURGBP', 'USDCHF', 'USDCAD', 'USDJPY']
def terminal_init(path_to_terminal, account):
'''
Функция осуществляет соединение с терминалом MT5
'''
if mt5.initialize(path_to_terminal, server=account[ 0 ], login=account[ 1 ], password=account[ 2 ]):
str1 = ' - соединение с терминалом {} билд {} установлено'
print(date_time.now().nice_view, str1.format(mt5.terminal_info().name, mt5. version ()[ 1 ]))
return True
else :
print(date_time.now().nice_view, ' - соединение с терминалом установить не удалось')
return False
def terminal_done():
'''
Функция завершает соединение с терминалом MT5
'''
try:
mt5.shutdown()
print('\n' + date_time.now().nice_view, ' - соединение с терминалом успешно завершено')
except:
print('\n' + date_time.now().nice_view, ' - соединение с терминалом завершить не удалось')
def dt_stamp_from_M5_view(M5_view):
return date_time( int (M5_view[ 0 : 4 ]), int (M5_view[ 4 : 6 ]), int (M5_view[ 6 : 8 ]), int (M5_view[ 8 : 10 ]), int (M5_view[ 10 : 12 ]))
def pips_definer(instrument):
'''
Функция возвращает величину пипса для инструмента, например для EURUSD - 0.0001 , для USDJPY - 0.01
'''
if instrument in ['EURUSD', 'GBPUSD', 'EURGBP', 'USDCHF', 'USDCAD']:
return0.0001
elif instrument in ['USDJPY']:
return0.01else :
return None
def save_prices_to_file(instrument, n= 100 ):
'''
Функция принимает инструмент, количество отсчётов цены n в таймфрейме М 5 ,
и сохраняет в файл (только сформировавшиеся полностью бары, время соответствует времени закрытия (!) бара)
'''
w = pips_definer(instrument)
tochn = int (abs(np. log10 (w))+ 1 )
path_file = os.path.join(work_catalog, instrument+'.txt')
bars = mt5.copy_rates_from_pos(instrument, mt5.TIMEFRAME_M5, 0 , n+ 1 ) # в случае ошибки mt5.copy_rates_from_pos возвращает None
try:
f = open(path_file, 'w')
for i in range( 0 , n+ 1 ):
bar = bars[i]
dt_stamp = date_time.fromtimestamp(bar[ 0 ], dt.timezone.utc) + dt.timedelta(hours= 1 , minutes= 5 )
open_ = str( round (bar[ 1 ], tochn))
high_ = str( round (bar[ 2 ], tochn))
low_ = str( round (bar[ 3 ], tochn))
close_ = str( round (bar[ 4 ], tochn))
if i != n:
f.write(dt_stamp.M5_view + ' ' + open_ + ' ' + high_ + ' ' + low_ + ' ' + close_ + '\n')
f.close()
print(date_time.now().nice_view, ' - котировки {} успешно записаны в файл'.format(instrument))
except:
print(date_time.now().nice_view, ' - котировки {} записать в файл не удалось'.format(instrument))
def read_file_with_prices(catalog, instrument):
'''
Функция принимает каталог, и наименование инструмента, читает в указанном каталоге файл с ценами для указанного инструмента
(формат данных: отсчёт времени в виде строки формата M5_view, open, high, low, close), проверяет цены на целостность данных.
Функция возвращает или массив ndarray (если всё успешно), или строку 'no data' (если данные не прочитались, или неполны)
'''
path_file = os.path.join(catalog, instrument+'.txt')
try:
f = open(path_file, 'r')
ndarray___with_prices_for_instrument = np.loadtxt(f, delimiter=' ', dtype='float64')
f.close()
except:
print(date_time.now().nice_view + ' - Файл с котировками для {} прочитать не удалось'.format(instrument))
return 'no data'
# проверка данных на целостность
timedelta_5 = dt.timedelta(minutes= 5 )
nx = ndarray___with_prices_for_instrument.shape[ 0 ]
for i in range( 1 , nx):
dt_stamp_i = dt_stamp_from_M5_view(str( int (ndarray___with_prices_for_instrument[i, 0 ])))
dt_stamp_im1 = dt_stamp_from_M5_view(str( int (ndarray___with_prices_for_instrument[i- 1 , 0 ])))
t_delta = dt_stamp_i - dt_stamp_im1
if t_delta != timedelta_5:
if t_delta >= dt.timedelta(hours= 47 ) and t_delta <= dt.timedelta(hours= 50 ):
pass # разрыв данных с вечера пятницы до понедельника
else :
t1 = ' - Котировки для {} неполны, и не будут переданы на выполнение расчётов\nИменно - ошибка при {}'
print((date_time.now().nice_view + t1).format(instrument, dt_stamp_im1.M5_view))
return 'no data'
return ndarray___with_prices_for_instrument
def read_all_files_with_prices(catalog, instruments):
'''
Функция принимает каталог, и список инструментов, читает в указанном каталоге файлы с ценами для указанных инструментов
с использованием функции read_file_with_prices.
Функция возвращает словарь prices_for_all_instruments с котировками по всем инструментам.
В этом словаре ключи - наименования инструментов, значения - словари с котировками по одному соответствующему инструменту.
В словарях с котировками по одному инструменту ключи - отсчёты даты-времени (класс date_time), значения - бары (класс bar),
кроме того предусмотрены ключи:
- 'is_data' - значение по ключу - True, если котировки в наличии, False - если функция чтения из файла вернула 'no data',
- 'instrument' - значение по ключу - инструмент (str);
- 'prices' - значение по ключу - массив котировок по инструменту (numpy.ndarray)
'''
dict___with_prices_for_all_instruments = {}
for instrument in instruments:
w = pips_definer(instrument)
ndarray___with_prices_for_instrument = read_file_with_prices(catalog, instrument)
dict___with_prices_for_instrument = {}
if type(ndarray___with_prices_for_instrument) == type('no data'):
dict___with_prices_for_instrument['is_data'] = False
else :
dict___with_prices_for_instrument['is_data'] = True
dict___with_prices_for_instrument['instrument'] = instrument
dict___with_prices_for_instrument['prices'] = ndarray___with_prices_for_instrument
for i in range( 0 , ndarray___with_prices_for_instrument.shape[ 0 ]):
dt_stamp = dt_stamp_from_M5_view(str( int (ndarray___with_prices_for_instrument[i, 0 ])))
dict___with_prices_for_instrument[dt_stamp] = Bar(instrument, 5 , dt_stamp,
ndarray___with_prices_for_instrument[i, 1 ],
ndarray___with_prices_for_instrument[i, 3 ],
ndarray___with_prices_for_instrument[i, 2 ],
ndarray___with_prices_for_instrument[i, 4 ], w)
dict___with_prices_for_all_instruments[instrument] = dict___with_prices_for_instrument
return dict___with_prices_for_all_instruments
def open_trade(buy_or_sell, instr, volume, price_in, price_sl, price_tp, w, deviation_in_pips):
'''
Функция осуществляет проверку: не ушёл ли текущий уровень цены от ожидаемого уровня price_in,
и если всё хорошо, совершает открытие сделки
'''
dopustimaya_delta_ot_price_in_in_pips = 5if buy_or_sell == 'buy':
trade_type = mt5. ORDER_TYPE_BUY
price = mt5.symbol_info_tick(instr).ask
comment = 'buy via Python'
elif buy_or_sell == 'sell':
trade_type = mt5. ORDER_TYPE_SELL
price = mt5.symbol_info_tick(instr).bid
comment = 'sell via Python'
if abs((price - price_in)/w) < dopustimaya_delta_ot_price_in_in_pips:
trade_request = {'action': mt5. TRADE_ACTION_DEAL ,
'symbol': instr,
'volume': volume,
'type': trade_type,
'price': price,
'sl': price_sl,
'tp': price_tp,
'deviation': deviation_in_pips* 10 ,
'magic': 12345 ,
'comment': comment,
'type_time': mt5. ORDER_TIME_GTC ,
'type_filling': mt5. ORDER_FILLING_FOK }
# отправление торгового запроса на сервер
result = mt5.order_send(trade_request)
# print(result)
if result.comment == 'Request executed':
if buy_or_sell == 'buy':
print(date_time.now().nice_view, ' - сделка на покупку {} открыта'.format(instr))
elif buy_or_sell == 'sell':
print(date_time.now().nice_view, ' - сделка на продажу {} открыта'.format(instr))
else :
if buy_or_sell == 'buy':
print(date_time.now().nice_view, ' - сделку на покупку {} открыть не удалось'.format(instr))
elif buy_or_sell == 'sell':
print(date_time.now().nice_view, ' - сделку на продажу {} открыть не удалось'.format(instr))
return result
else :
print(date_time.now().nice_view, ' - цена ушла от ожидаемой > 5 пипс, сделку по {} не открываю'.format(instr))
return None
def close_trade(position):
'''
Функция осуществляет закрытие сделки
'''
instr = position.symbol
if position.tp > position.sl: # buy
trade_type = mt5. ORDER_TYPE_SELL # если позиция buy, то для её закрытия нужно sell
price = mt5.symbol_info_tick(instr).bid
elif position.sl > position.tp: # sell
trade_type = mt5. ORDER_TYPE_BUY # если позиция sell, то для её закрытия нужно buy
price = mt5.symbol_info_tick(instr).ask
position_id = position.ticket
volume = position.volume
trade_request = {'action': mt5. TRADE_ACTION_DEAL ,
'symbol': instr,
'volume': volume,
'type': trade_type,
'position': position_id,
'price': price,
#'deviation': deviation_in_pips* 10 ,
'magic': position.magic,
'comment': 'close via python',
'type_time': mt5. ORDER_TIME_GTC ,
'type_filling': mt5. ORDER_FILLING_FOK }
# отправление торгового запроса на сервер
result = mt5.order_send(trade_request)
if result.comment == 'Request executed':
print(date_time.now().nice_view, ' - сделка {} по {} закрыта'.format(position_id, instr))
return result
def main(N):
'''
Главная функция, обеспечивающая в бесконечном цикле связь с терминалом,
сохранение котировок, и запуск функции, осуществляющей торговлю
'''
dt_start = date_time.now()
dt_write = dt_stamp_from_M5_view(dt_start.M5_view) + dt.timedelta(minutes= 5 , seconds= 10 )
print('\n' + dt_start.nice_view, ' - начал работу, бездействую до ' + dt_write.nice_view + '\n')
timedelta_sleep = dt_write - date_time.now()
time.sleep(timedelta_sleep.seconds)
while True:
# установка соединения с MetaTrader5
if terminal_init(os.path.join('C:\\', 'Program Files', 'Alpari MT5', 'terminal64.exe'), work_account):
# запись цен в файлы: для всех инструментов, N отсчётов
if (dt. datetime .now() - dt_write) < dt.timedelta(seconds= 10 ):
print('\n' + date_time.now().nice_view + ' - начинаю запись цен в файлы для всех инструментов')
for instrument in instruments:
save_prices_to_file(instrument, N)
# пауза 5 секунд после записи файлов с ценами, возможно необходимых для открытия в Mathcad,
# или ещё зачем, если в них нет нужды, желающие могут переписать код, исключив бессмысленную
# последовательность записи файлов, и затем чтения файлов, сразу сформировав нужную им структуру данных
time.sleep( 5 )
# определяем значение последнего отсчёта времени, который должен быть в файлах котировок, если они актуальны
# (в выходные дни это будет не так, а в будни, пока рынок открыт - так)
fx_dt_stamp_now = dt_stamp_from_M5_view(date_time.now().M5_view)
print('\n\n'+date_time.now().nice_view, '- начинаю вычисления для отсчёта времени {}'.format(fx_dt_stamp_now.M5_view))
# получаем словарь с ценами для всех инструментов
dict___with_prices_for_all_instruments = read_all_files_with_prices(work_catalog, instruments)
# демонстрация актуальности котировок,
# поскольку сейчас выходной, то последний отсчёт времени в файлах данных не совпадает с текущим, не суть
for instrument in instruments:
if dict___with_prices_for_all_instruments[instrument]['is_data']:
str1 = 'Последний отсчёт в файле с ценами для {}: {}'
print(str1.format(instrument, str( int (dict___with_prices_for_all_instruments[instrument]['prices'][N- 1 , 0 ]))))
# отобразим значения последних n отсчётов цен закрытия баров, и SMA101, вычисленной по ценам закрытия баров
for instrument in instruments:
dict___with_prices_for_instrument = dict___with_prices_for_all_instruments[instrument]
if dict___with_prices_for_instrument['is_data']:
AData = dict___with_prices_for_instrument['prices']
Ax_DTID = AData[:, 0 ] # столбец отсчётов даты-времени в виде M5_view в N строк, пока низачем не нужен
Ax_close = AData[:, 4 ] # столбец отсчётов цен закрытия в N строк
A_DTID = Ax_DTID[Ax_close.size-n-d:Ax_close.size-d] # столбец отсчётов даты-времени в виде M5_view в n строк
A_close = Ax_close[Ax_close.size-n-d:Ax_close.size-d] # столбец отсчётов цен закрытия в n строк
print('Последние {} отсчётов цен закрытия для {}:'.format(n, instrument))
print(A_close)
z = 50 # параметр, задающий запаздывание скользящей средней, для z= 50 скользящая средняя по 1 + 2 * 50 = 101 отсчёту
A_close_s = Functions.SMA(Ax_close, 1 + 2 *z, 0 , n, d)
print('Последние {} отсчётов SMA( 101 ) по ценам закрытия для {}:'.format(n, instrument))
print(A_close_s)
# завершение соединения с MetaTrader5
terminal_done()
# определение параметров ожидания до следующего выполнения тела цикла
dt_start = date_time.now()
dt_write = dt_stamp_from_M5_view(dt_start.M5_view) + dt.timedelta(minutes= 5 , seconds= 10 )
timedelta_sleep = dt_write - dt_start
print(date_time.now().nice_view + ' - засыпаю до {}\n\n\n\n\n'.format(dt_write.nice_view))
time.sleep(timedelta_sleep.seconds)
if __name__ == '__main__':
main(N)
# запрос открытых сделок по инструменту
for instrument in instruments:
current_positions_for_instrument = mt5.positions_get(symbol = instrument)
Nsell_Nbuy = Nsell_Nbuy_calculator(current_positions_for_instrument)
print(date_time.now().nice_view, ' - по {} открытых сделок sell {}, открытых сделок buy {}'.format(instrument,
Nsell_Nbuy[0],
Nsell_Nbuy[1]))
def SL_TP_control(instrument, current_positions):
'''
Функция принимает перечень открытых позиций.
Функция осуществляет контроль выставленности SL и TP у открытых позиций,
в случае обнаружения сделки без SL или TP - закрывает (пытается закрыть) все сделки из полученного перечня.
'''
Nsell_Nbuy = Nsell_Nbuy_calculator(current_positions)
if Nsell_Nbuy[0] > 0 or Nsell_Nbuy[1] > 0:
print(date_time.now().nice_view, ' - осуществляю проверку выставленности TP и SL у открытых сделок по {}'.format(instrument))
print(date_time.now().nice_view, ' - открытых сделок sell {}, открытых сделок buy {}'.format(Nsell_Nbuy[0], Nsell_Nbuy[1]))
s = 0for i in range(len(current_positions)):
try:
if current_positions[i].tp > current_positions[i].sl or current_positions[i].sl > current_positions[i].tp:
s += 1
except:
print(date_time.now().nice_view, ' - обнаружена сделка по {} с отсутствующим SL или TP - закрываю!'.format(instrument))
close_trade(current_positions[i])
time.sleep(0.5)
if s == len(current_positions):
print(date_time.now().nice_view, ' - выставленность TP и SL у открытых сделок по {} - OK'.format(instrument))
def profit_calculator(instrument, position):
'''
Функция принимает позицию, и возвращает текущий результат, в пипсах.
'''
w = pips_definer(instrument)
buy_sell = buy_or_sell_opredelitel(position)
if buy_sell == 'sell':
bs = -1
elif buy_sell == 'buy':
bs = 1if buy_sell == 'buy' or buy_sell == 'sell':
profit_in_pips = round((position.price_current - position.price_open)/w, 1)*bs
return profit_in_pips
return None
import os, time
import datetime as dt
from json import loads, dump
from random import randint
import numpy as np
from Classes import date_time, Bar
import Functions
import MetaTrader5 as mt5
N = 1000 # количество отсчётов, сохраняемых в файлах котировок
n = 5
d = 0
price_SMA_razn_Level = 10 # модуль разности между ценой и SMA, при превышении этого порога открываем сделку
N_sd_sell_max = 2 # максимальное количество сделок типа sell по одному инструменту
N_sd_buy_max = 2 # максимальное количество сделок типа buy по одному инструменту
SL = 50; TP = 50 # уровни SL и TP, в пипсах
volume = 0.01 # объём сделок
account_demo = ['Alpari-MT5-Demo', 51056680, 'pxav2sxs']
work_account = account_demo
work_catalog = 'Z:\\fx_for_forum\\fx\\'
instruments = ['EURUSD', 'GBPUSD', 'EURGBP', 'USDCHF', 'USDCAD', 'USDJPY']
def terminal_init(path_to_terminal, account):
'''
Функция осуществляет соединение с терминалом MT5
'''
if mt5.initialize(path_to_terminal, server=account[0], login=account[1], password=account[2]):
str1 = ' - соединение с терминалом {} билд {} установлено'
print(date_time.now().nice_view, str1.format(mt5.terminal_info().name, mt5.version()[1]))
return True
else:
print(date_time.now().nice_view, ' - соединение с терминалом установить не удалось')
return False
def terminal_done():
'''
Функция завершает соединение с терминалом MT5
'''
try:
mt5.shutdown()
print('\n' + date_time.now().nice_view, ' - соединение с терминалом успешно завершено')
except:
print('\n' + date_time.now().nice_view, ' - соединение с терминалом завершить не удалось')
def dt_stamp_from_M5_view(M5_view):
return date_time(int(M5_view[0:4]), int(M5_view[4:6]), int(M5_view[6:8]), int(M5_view[8:10]), int(M5_view[10:12]))
def pips_definer(instrument):
'''
Функция возвращает величину пипса для инструмента, например для EURUSD - 0.0001, для USDJPY - 0.01
'''
if instrument in ['EURUSD', 'GBPUSD', 'EURGBP', 'USDCHF', 'USDCAD']:
return 0.0001
elif instrument in ['USDJPY']:
return 0.01
else:
return None
def save_prices_to_file(instrument, n=100):
'''
Функция принимает инструмент, количество отсчётов цены n в таймфрейме М5,
и сохраняет в файл (только сформировавшиеся полностью бары, время соответствует времени закрытия (!) бара)
'''
w = pips_definer(instrument)
tochn = int(abs(np.log10(w))+1)
path_file = os.path.join(work_catalog, instrument+'.txt')
bars = mt5.copy_rates_from_pos(instrument, mt5.TIMEFRAME_M5, 0, n+1) # в случае ошибки mt5.copy_rates_from_pos возвращает None
try:
f = open(path_file, 'w')
for i in range(0, n+1):
bar = bars[i]
dt_stamp = date_time.fromtimestamp(bar[0], dt.timezone.utc) + dt.timedelta(hours=1, minutes=5)
open_ = str(round(bar[1], tochn))
high_ = str(round(bar[2], tochn))
low_ = str(round(bar[3], tochn))
close_ = str(round(bar[4], tochn))
if i != n:
f.write(dt_stamp.M5_view + ' ' + open_ + ' ' + high_ + ' ' + low_ + ' ' + close_ + '\n')
f.close()
print(date_time.now().nice_view, ' - котировки {} успешно записаны в файл'.format(instrument))
except:
print(date_time.now().nice_view, ' - котировки {} записать в файл не удалось'.format(instrument))
def read_file_with_prices(catalog, instrument):
'''
Функция принимает каталог, и наименование инструмента, читает в указанном каталоге файл с ценами для указанного инструмента
(формат данных: отсчёт времени в виде строки формата M5_view, open, high, low, close), проверяет цены на целостность данных.
Функция возвращает или массив ndarray (если всё успешно), или строку 'no data' (если данные не прочитались, или неполны)
'''
path_file = os.path.join(catalog, instrument+'.txt')
try:
f = open(path_file, 'r')
ndarray___with_prices_for_instrument = np.loadtxt(f, delimiter=' ', dtype='float64')
f.close()
except:
print(date_time.now().nice_view + ' - Файл с котировками для {} прочитать не удалось'.format(instrument))
return 'no data'
# проверка данных на целостность
timedelta_5 = dt.timedelta(minutes=5)
nx = ndarray___with_prices_for_instrument.shape[0]
for i in range(1, nx):
dt_stamp_i = dt_stamp_from_M5_view(str(int(ndarray___with_prices_for_instrument[i, 0])))
dt_stamp_im1 = dt_stamp_from_M5_view(str(int(ndarray___with_prices_for_instrument[i-1, 0])))
t_delta = dt_stamp_i - dt_stamp_im1
if t_delta != timedelta_5:
if t_delta >= dt.timedelta(hours=47) and t_delta <= dt.timedelta(hours=50):
pass # разрыв данных с вечера пятницы до понедельника
else:
t1 = ' - Котировки для {} неполны, и не будут переданы на выполнение расчётов\nИменно - ошибка при {}'
print((date_time.now().nice_view + t1).format(instrument, dt_stamp_im1.M5_view))
return 'no data'
return ndarray___with_prices_for_instrument
def read_all_files_with_prices(catalog, instruments):
'''
Функция принимает каталог, и список инструментов, читает в указанном каталоге файлы с ценами для указанных инструментов
с использованием функции read_file_with_prices.
Функция возвращает словарь prices_for_all_instruments с котировками по всем инструментам.
В этом словаре ключи - наименования инструментов, значения - словари с котировками по одному соответствующему инструменту.
В словарях с котировками по одному инструменту ключи - отсчёты даты-времени (класс date_time), значения - бары (класс bar),
кроме того предусмотрены ключи:
- 'is_data' - значение по ключу - True, если котировки в наличии, False - если функция чтения из файла вернула 'no data',
- 'instrument' - значение по ключу - инструмент (str);
- 'prices' - значение по ключу - массив котировок по инструменту (numpy.ndarray)
'''
dict___with_prices_for_all_instruments = {}
for instrument in instruments:
w = pips_definer(instrument)
ndarray___with_prices_for_instrument = read_file_with_prices(catalog, instrument)
dict___with_prices_for_instrument = {}
if type(ndarray___with_prices_for_instrument) == type('no data'):
dict___with_prices_for_instrument['is_data'] = False
else:
dict___with_prices_for_instrument['is_data'] = True
dict___with_prices_for_instrument['instrument'] = instrument
dict___with_prices_for_instrument['prices'] = ndarray___with_prices_for_instrument
for i in range(0, ndarray___with_prices_for_instrument.shape[0]):
dt_stamp = dt_stamp_from_M5_view(str(int(ndarray___with_prices_for_instrument[i, 0])))
dict___with_prices_for_instrument[dt_stamp] = Bar(instrument, 5, dt_stamp,
ndarray___with_prices_for_instrument[i, 1],
ndarray___with_prices_for_instrument[i, 3],
ndarray___with_prices_for_instrument[i, 2],
ndarray___with_prices_for_instrument[i, 4], w)
dict___with_prices_for_all_instruments[instrument] = dict___with_prices_for_instrument
return dict___with_prices_for_all_instruments
def open_trade(buy_or_sell, instr, volume, price_in, price_sl, price_tp, w, deviation_in_pips):
'''
Функция осуществляет проверку: не ушёл ли текущий уровень цены от ожидаемого уровня price_in,
и если всё хорошо, совершает открытие сделки
'''
dopustimaya_delta_ot_price_in_in_pips = 5
if buy_or_sell == 'buy':
trade_type = mt5.ORDER_TYPE_BUY
price = mt5.symbol_info_tick(instr).ask
comment = 'buy via Python'
elif buy_or_sell == 'sell':
trade_type = mt5.ORDER_TYPE_SELL
price = mt5.symbol_info_tick(instr).bid
comment = 'sell via Python'
if abs((price - price_in)/w) < dopustimaya_delta_ot_price_in_in_pips:
trade_request = {'action': mt5.TRADE_ACTION_DEAL,
'symbol': instr,
'volume': volume,
'type': trade_type,
'price': price,
'sl': price_sl,
'tp': price_tp,
'deviation': deviation_in_pips*10,
'magic': 12345,
'comment': comment,
'type_time': mt5.ORDER_TIME_GTC,
'type_filling': mt5.ORDER_FILLING_FOK}
# отправление торгового запроса на сервер
result = mt5.order_send(trade_request)
# print(result)
if result.comment == 'Request executed':
if buy_or_sell == 'buy':
print(date_time.now().nice_view, ' - сделка на покупку {} открыта'.format(instr))
elif buy_or_sell == 'sell':
print(date_time.now().nice_view, ' - сделка на продажу {} открыта'.format(instr))
else:
if buy_or_sell == 'buy':
print(date_time.now().nice_view, ' - сделку на покупку {} открыть не удалось'.format(instr))
elif buy_or_sell == 'sell':
print(date_time.now().nice_view, ' - сделку на продажу {} открыть не удалось'.format(instr))
return result
else:
print(date_time.now().nice_view, ' - цена ушла от ожидаемой >5 пипс, сделку по {} не открываю'.format(instr))
return None
def close_trade(position):
'''
Функция осуществляет закрытие сделки
'''
instr = position.symbol
if position.tp > position.sl: # buy
trade_type = mt5.ORDER_TYPE_SELL # если позиция buy, то для её закрытия нужно sell
price = mt5.symbol_info_tick(instr).bid
elif position.sl > position.tp: # sell
trade_type = mt5.ORDER_TYPE_BUY # если позиция sell, то для её закрытия нужно buy
price = mt5.symbol_info_tick(instr).ask
position_id = position.ticket
volume = position.volume
trade_request = {'action': mt5.TRADE_ACTION_DEAL,
'symbol': instr,
'volume': volume,
'type': trade_type,
'position': position_id,
'price': price,
#'deviation': deviation_in_pips*10,
'magic': position.magic,
'comment': 'close via python',
'type_time': mt5.ORDER_TIME_GTC,
'type_filling': mt5.ORDER_FILLING_FOK}
# отправление торгового запроса на сервер
result = mt5.order_send(trade_request)
if result.comment == 'Request executed':
print(date_time.now().nice_view, ' - сделка {} по {} закрыта'.format(position_id, instr))
return result
def buy_or_sell_opredelitel(position):
try:
tp = position.tp
sl = position.sl
if tp > sl:
return 'buy'
elif sl > tp:
return 'sell'
else:
return None
except:
return None
def Nsell_Nbuy_calculator(current_positions):
'''
Функция принимает перечень открытых позиций.
Функция возвращает кортеж (Nsell, Nbuy) с количествами позиций sell и buy, соответственно
'''
Nsell = 0
Nbuy = 0
if len(current_positions) == 0:
return (Nsell, Nbuy)
else:
for position in current_positions:
if buy_or_sell_opredelitel(position) == 'sell':
Nsell += 1
elif buy_or_sell_opredelitel(position) == 'buy':
Nbuy += 1
return (Nsell, Nbuy)
def SL_TP_control(instrument, current_positions):
'''
Функция принимает перечень открытых позиций.
Функция осуществляет контроль выставленности SL и TP у открытых позиций,
в случае обнаружения сделки без SL или TP - закрывает (пытается закрыть) все сделки из полученного перечня.
'''
Nsell_Nbuy = Nsell_Nbuy_calculator(current_positions)
if Nsell_Nbuy[0] > 0 or Nsell_Nbuy[1] > 0:
print(date_time.now().nice_view, ' - осуществляю проверку выставленности TP и SL у открытых сделок по {}'.format(instrument))
print(date_time.now().nice_view, ' - открытых сделок sell {}, открытых сделок buy {}'.format(Nsell_Nbuy[0], Nsell_Nbuy[1]))
s = 0
for i in range(len(current_positions)):
try:
if current_positions[i].tp > current_positions[i].sl or current_positions[i].sl > current_positions[i].tp:
s += 1
except:
print(date_time.now().nice_view, ' - обнаружена сделка по {} с отсутствующим SL или TP - закрываю!'.format(instrument))
close_trade(current_positions[i])
time.sleep(0.5)
if s == len(current_positions):
print(date_time.now().nice_view, ' - выставленность TP и SL у открытых сделок по {} - OK'.format(instrument))
def profit_calculator(instrument, position):
'''
Функция принимает позицию, и возвращает текущий результат, в пипсах.
'''
w = pips_definer(instrument)
buy_sell = buy_or_sell_opredelitel(position)
if buy_sell == 'sell':
bs = -1
elif buy_sell == 'buy':
bs = 1
if buy_sell == 'buy' or buy_sell == 'sell':
profit_in_pips = round((position.price_current - position.price_open)/w, 1)*bs
return profit_in_pips
return None
def main(N):
'''
Главная функция, обеспечивающая в бесконечном цикле связь с терминалом,
сохранение котировок, и запуск функции, осуществляющей торговлю
'''
dt_start = date_time.now()
dt_write = dt_stamp_from_M5_view(dt_start.M5_view) + dt.timedelta(minutes=5, seconds=10)
print('\n' + dt_start.nice_view, ' - начал работу, бездействую до ' + dt_write.nice_view + '\n')
timedelta_sleep = dt_write - date_time.now()
time.sleep(timedelta_sleep.seconds)
while True:
# установка соединения с MetaTrader5
if terminal_init(os.path.join('C:\\', 'Program Files', 'Alpari MT5', 'terminal64.exe'), work_account):
# запись цен в файлы: для всех инструментов, N отсчётов
if (dt.datetime.now() - dt_write) < dt.timedelta(seconds=10):
print('\n' + date_time.now().nice_view + ' - начинаю запись цен в файлы для всех инструментов')
for instrument in instruments:
save_prices_to_file(instrument, N)
# пауза 5 секунд после записи файлов с ценами, возможно необходимых для открытия в Mathcad,
# или ещё зачем, если в них нет нужды, желающие могут переписать код, исключив бессмысленную
# последовательность записи файлов, и затем чтения файлов, сразу сформировав нужную им структуру данных
time.sleep(5)
# определяем значение последнего отсчёта времени, который должен быть в файлах котировок, если они актуальны
# (в выходные дни это будет не так, а в будни, пока рынок открыт - так)
fx_dt_stamp_now = dt_stamp_from_M5_view(date_time.now().M5_view)
print('\n\n'+date_time.now().nice_view, ' - начинаю вычисления для отсчёта времени {}'.format(fx_dt_stamp_now.M5_view))
# получаем словарь с ценами для всех инструментов
dict___with_prices_for_all_instruments = read_all_files_with_prices(work_catalog, instruments)
# вычислим значения последних n отсчётов цен закрытия баров, и SMA101, вычисленной по ценам закрытия баров,
# если цена выше SMA на price_SMA_razn_Level, в пипсах, и открытых сделок на продажу по этому инструменту меньше,
# чем N_sd_sell_max, то открываем сделку на продажу,
# если цена ниже SMA на price_SMA_razn_Level, в пипсах, и открытых сделок на покупку по этому инструменту меньше,
# чем N_sd_buy_max, то открываем сделку на покупку.
for instrument in instruments:
dict___with_prices_for_instrument = dict___with_prices_for_all_instruments[instrument]
current_positions_for_instrument = mt5.positions_get(symbol = instrument)
Nsell_Nbuy = Nsell_Nbuy_calculator(current_positions_for_instrument)
if dict___with_prices_for_instrument['is_data']:
w = pips_definer(instrument) # величина пипса для инструмента
tochn = int(abs(np.log10(w))+1)
AData = dict___with_prices_for_instrument['prices']
Ax_close = AData[:, 4] # столбец отсчётов цен закрытия в N строк
A_close = Ax_close[Ax_close.size-n-d:Ax_close.size-d] # столбец отсчётов цен закрытия в n строк
z = 50 # параметр, задающий запаздывание скользящей средней, для z=50 скользящая средняя по 1+2*50=101 отсчёту
A_close_s = Functions.SMA(Ax_close, 1+2*z, 0, n, d)
price_SMA_razn_for_instrument = round((A_close[n-1] - A_close_s[n-1])/w, 1)
print('\n')
str1 = ' - для {} крайние справа отсчёты цены {}, SMA {}, разность {} пипс'
print(date_time.now().nice_view, str1.format(instrument, A_close[n-1], round(A_close_s[n-1], tochn),
price_SMA_razn_for_instrument))
if abs(price_SMA_razn_for_instrument) < price_SMA_razn_Level:
print(date_time.now().nice_view, ' - разность с SMA не превышает порога {} пипс, ничего не делаю'.format(price_SMA_razn_Level))
elif abs(price_SMA_razn_for_instrument) > price_SMA_razn_Level:
if price_SMA_razn_for_instrument > price_SMA_razn_Level and Nsell_Nbuy[0] < N_sd_sell_max:
print(date_time.now().nice_view, ' - разность с SMA превышает порог {} пипс, продаю {}'.format(price_SMA_razn_Level,
instrument))
open_trade('sell', instrument, volume, A_close[n-1], A_close[n-1]+SL*w, A_close[n-1]-TP*w, w, 2)
time.sleep(1)
if price_SMA_razn_for_instrument < -price_SMA_razn_Level and Nsell_Nbuy[1] < N_sd_buy_max:
print(date_time.now().nice_view, ' - разность с SMA превышает порог {} пипс, покупаю {}'.format(price_SMA_razn_Level,
instrument))
open_trade('buy', instrument, volume, A_close[n-1], A_close[n-1]-SL*w, A_close[n-1]+TP*w, w, 2)
time.sleep(1)
# запрос открытых сделок по инструменту
print('\n')
for instrument in instruments:
current_positions_for_instrument = mt5.positions_get(symbol = instrument)
Nsell_Nbuy = Nsell_Nbuy_calculator(current_positions_for_instrument)
print(date_time.now().nice_view, ' - по {} открытых сделок sell {}, открытых сделок buy {}'.format(instrument,
Nsell_Nbuy[0],
Nsell_Nbuy[1]))
# завершение соединения с MetaTrader5
terminal_done()
# определение параметров ожидания до следующего выполнения тела цикла
dt_start = date_time.now()
dt_write = dt_stamp_from_M5_view(dt_start.M5_view) + dt.timedelta(minutes=5, seconds=10)
timedelta_sleep = dt_write - dt_start
print(date_time.now().nice_view + ' - засыпаю до {}\n\n\n\n\n'.format(dt_write.nice_view))
time.sleep(timedelta_sleep.seconds)
if __name__ == '__main__':
main(N)
我支持这个话题的发起人,我已经多次借用mql作为4和5,我想说的是,我个人没有什么愿望去学习这种只能在这里交易的语言 ...
好吧,这要么是白说,要么是因为你不了解这个问题。你真的要把指标算法重新写一遍吗?这就像从伏尔加格勒经海参崴到莫斯科。还有一件事,所有的指标都考虑到了历史。也就是说,如果你把一个月的数据(条形图),按照你的算法计算指标,并与终端比较,你的计算结果将是不同的。
我也不明白这句话。
根据我所写的内容,事实证明,Python的知识有很大一层:)你打开一个编辑器,你已经知道python--它是如此简单,而打开mql,你却什么都不知道。
同时,把完全面向平台的 mql称为 "过时的 "工具......python创建于1991年,这要早得多。
我在这个主题中看到的,用python写的,在mql中非常容易实现
---
嗯,作为一个一般的想法,这很有趣,但不是更多。
此外,他没有利用Python的优势,也不是 "Python风格"。这就像用螺丝刀敲打钉子,锤子是老式的。
我怀疑你家里唯一的餐具是勺子--你可以做汤或做蛋糕,用它更安全。
)))
如果你喜欢它,就使用Python,但不要把它作为主题--不要创建你自己的自定义数据类型--条形等等,不要写你自己的计算......并使用现有的解决方案,否则使用这种语言就没有意义,你还不如自己写神经网络包;)
是的)顺便说一下,Python上没有那些交易员的函数库,或者说如果你能用几行字写出一个系列的完整统计分析,你就不需要MA)...
是的)顺便说一下,没有Python库的各种近似交易功能,或者说如果你能用几行字写出一个完整的系列统计分析,那么就不再需要MA了)...
最好的101个Python算法交易库 | PythonRepo
昨天回不了论坛。我会继续。我开始了一个新的模拟账户,上面是工具名称,最后没有'_i',所以我更正了这部分的代码。
我会继续循序渐进的慢动作,一种微教程,可能会派上用场。
让我们引入一个变量 n(小)——可以说是窗口的长度。也就是说,在具有价格的文件中,N 个读数,例如 1000 和 n,让我们设置,例如,10、100 或 288(一天,如果时间框架是 M5)。
对我来说,变量 d 意味着这个窗口在时间上的转移,进入过去。让我们设置 d = 0。
例如,我们将显示 10 个收盘价和 101 数量级的 SMA 读数(读数之间延迟 50 个间隔):
工作结果:
让我们学习如何询问终端关于市场上当前交易的情况,可以说是对工具的询问。
我将介绍函数
让它接受符号的开仓列表并返回元组( 卖出的交易数量,买入的交易数量)。
在主函数中,在函数terminal_done()之前添加这个片段
结果(为了输出的缘故,n被减少到5)。
我提议开始实际开仓交易。例如:如果价格比均线高一些:开出卖出交易,如果价格比均线低一些:开出买入交易。
我建议再增加几个功能:在SL和TP方面控制未完成的交易,如果没有的话就关闭它们,以及一个以点为单位返回当前结果(利润或损失)的功能。
我们必须记住以某种方式处理订单已经在历史中,但不在活动位置的情况,在这种情况下不要重新发送订单开仓。
这种情况时有发生,例如,通过Trade.mqh工作并不能解决这个问题(至少,以前没有--我很早就放弃了Trade.mqh)。
有时情况恰恰相反--平仓的指令已经在历史中出现,而头寸仍然可见。
我们必须记住以某种方式处理订单已经在历史中,但不在活动位置的情况,在这种情况下不要重新发送订单开仓。
这种情况时有发生,例如,通过Trade.mqh工作并不能解决这个问题(至少,以前没有--我很早就放弃了Trade.mqh)。
有时情况恰恰相反--平仓指令已经在历史中出现,而头寸仍然是可见的。
我展示了如何询问终端关于未结头寸的情况。没有什么能阻止我们以这样的方式编写代码:如果职位已经存在,我们就不需要重新发送请求,如果不存在--我们就会。特别是,在发送一个请求后,返回的对象,其属性中的一切,我们可以看到它是否正常,或存在什么样的错误,并基于这一行为。这里没有任何问题。
最好的101个Python算法交易库 | PythonRepo
它已经是104)它是105)。
到目前为止,TradeLogic.py文件的全部代码(是的,它很原始,但我确信它可能为一些人打开使用Metatrader 5和Python进行交易的大门)
工作成果。
在我看来,所展示的最原始、最基本的代码片断已经很清楚地表明,实现绝对的任何逻辑、任何计算、比较、通过各种标准控制开放的交易、在某些条件下自动关闭交易、在命令行上和通过写入文件保持日志,等等,等等--任何没有任何限制。
Z.U.2 Till现在使用的是Sdelka类,一般来说,把这个类的对象传到函数中,把它们写成.json等文件是很方便的,--但不知为什么有点累,我想那些想了解的人,我可以在这里帮点忙。如果你愿意,你可以在一个图形界面上拧。
我强烈建议使用Python+metatrader5库进行交易。
我已经展示了如何轮询终端的未结头寸。没有什么可以阻止你编写代码,以便如果已经有一个位置,那么你就不需要重新发送请求,如果没有--发送。特别是,在发送一个请求后,对象被返回,它有所有的属性,我们可以看到它是否正常打开或有一个错误,并基于这个行为。这里没有任何问题。
再一次,该命令已经被执行,并被传入历史。它不再处于主动地位。该职位已经被打开,但它还不可见;请求没有显示它。
通常情况下,这是一个非常短的时间间隔,很难达到,特别是不一定能达到。
然而,在早上开盘时,这种情况可能连几秒钟都持续不了,而是几分钟就会出现缺口和大量的订单。
为了更清楚:TRADE_TRANSACTION_ORDER_DELETE比TRADE_TRANSACTION_HISTORY_ADD或TRADE_TRANSACTION_DEAL_ADD来得更早。
而且,我们可能在某个时候看不到活跃或历史上的订单,或者我们可能看不到任何订单或交易。