파이썬으로 거래하기 - 페이지 4

 
Malik Arykov # :

MT5와 python의 통합이 완료되지 않았음을 의미합니다. 지표 값을 직접 가져올 수 없습니다.

mql에 데이터 저장
 int i = iBarShift ( _Symbol , PERIOD_CURRENT ,startTime);
 string nm = _Symbol + "_Inputs.csv" ;
 int h = FileOpen (nm, FILE_CSV | FILE_WRITE | FILE_COMMON , ";" );
 double d[ 2 ];
 while (i > 0 ) {
  d[ 0 ]=iСustom( _Symbol , PERIOD_CURRENT , "Ind_1" , 0 ,i);
  d[1]=iСustom( _Symbol , PERIOD_CURRENT , "Ind_2" , 0 ,i);
   FileWrite (h,d[ 0 ],d[ 1 ]);
  i--;
 }
 FileClose (h);

파이썬에서 데이터 읽기

import pandas as pd

_Symbol = "EURUSD"
_Base = "C:\\Users\\serg\\AppData\\Roaming\\MetaQuotes\\Terminal\\Common\\Files\\"

url = _Base+ _Symbol + "_Inputs.csv"
X=pd.read_csv(url,delimiter= ';' ,header=None)
 
Mikhael1983 # :

주제의 목표는 5센트 정도로 간단합니다. 터미널과의 통신 초기화, 견적 요청, 서버에 트랜잭션 열기 또는 닫기 요청 등과 같은 코드 조각을 단순히 복사하여 모든 사람이 Python에서 알고리즘 거래를 시작할 수 있도록 하는 것입니다. 등. 더욱이 이를 위해 매우 편리한 언어로 논리에만 집중하십시오.

글쎄요 ... 논리는 알고리즘 거래에 충분하지 않습니다. "모든 사람"이 코드 조각을 삽입하고 실제 거래에 들어가기 전에 거래 전략을 테스트해야 하는 논리


글쎄, 어쨌든, "비 신화적인"목표에 행운을 빕니다.

)))

 

가격을 파일에 저장할 필요가 없는 사람들은 코드를 약간 다시 작성하고 "파일에 쓰기 - 파일에서 읽기"가 아니라 바로 필요한 데이터 구조 만 하면 됩니다. 여기 여러 면에서 첫 단계를 밟고 싶은 사람들을 위해 원시적인 것들을 보여줍니다.

그러나 목록, 튜플, 사전 등과 같은 개념에 이미 익숙한 사람들은

read_all_files_with_prices 함수를 사용하여 가격 파일에서 읽는 것이 좋습니다. 이 함수는 read_file_with_prices 함수를 사용하여 각 기호에 대한 가격이 있는 파일을 읽습니다.

read_file_with_prices 함수 가 원래 가격 파일에 해당하는 행과 열이 있는 numpy.ndarray 배열(가격이 성공적으로 읽고 데이터 무결성 검사를 통과한 경우 각 요소의 유형은 numpy.float64임) 또는 문자열 ' 데이터가 읽히지 않았거나 불완전한 경우 데이터 없음'입니다.

read_all_files_with_prices 함수 가 모든 상품에 대한 따옴표가 있는 사전을 반환하도록 합니다. 이 사전의 키를 악기 이름, 값 - 하나의 해당 악기에 대한 따옴표가 있는 사전으로 설정합니다. 하나의 도구에 대한 따옴표가 있는 사전에서 키는 날짜-시간 판독값(date_time 클래스)이고 값은 막대(막대 클래스)이며 또한 키를 제공할 것을 제안합니다.

  • 'is_data': 키별 값 - 따옴표를 사용할 수 있는 경우 True, False - 파일에서 읽는 기능이 '데이터 없음'을 반환한 경우,

  • 'instrument': 키별 값 - 기기(str);

  • '가격': 키별 값 - 상품 가격 배열(numpy.ndarray)

요컨대 다음과 같은 데이터 구조를 제안합니다.


 

Python 코드는 IDE/편집기/웹사이트의 스크린샷으로 가장 잘 배치됩니다.

적어도 코드 주석을 강조 표시하지 않는 부분은 가독성이 떨어지고 본문과 병합됩니다.

 

파일 읽기 및 위의 데이터 구조 생성을 위한 기능 추가:

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_sd_sell_max = 3 # максимальное количество сделок типа sell по одному инструменту
N_sd_buy_max = 3 # максимальное количество сделок типа buy по одному инструменту
volume = 0.01 # объём сделок 
account_demo = ['Alpari-MT5-Demo', 12345678 , 'password']
work_account = account_demo 
work_catalog = 'Z:\\fx_for_forum\\fx\\'
instruments = ['EURUSD_i', 'GBPUSD_i', 'EURGBP_i', 'USDCHF_i', 'USDCAD_i', 'USDJPY_i']



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_i', 'GBPUSD_i', 'EURGBP_i', 'USDCHF_i', 'USDCAD_i']:
         return 0.0001
    elif instrument in ['USDJPY_i']:
         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 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 ]))))
           
           
           
            # завершение соединения с 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)
 
Maxim Kuznetsov # :

Python 코드는 IDE/편집기/웹사이트의 스크린샷으로 가장 잘 배치됩니다.

적어도 코드 주석을 강조 표시하지 않는 부분은 가독성이 떨어지고 본문과 병합됩니다.

그러나 복사하여 IDE에서 열 수 있으며 그림에서 수동으로 다시 입력할 수 있습니다. 아마도 ...


위 프로그램의 작동 방식:



원칙적으로 거의 모든 것이 데이터 분석, 거래 결정 및 실행을 시작할 준비가 되어 있습니다.

 
Mikhael1983 # :

그러나 복사하여 IDE에서 열 수 있으며 그림에서 수동으로 다시 입력할 수 있습니다. 아마도 ...


아무도 코드 복사-붙여넣기를 귀찮게 할 것 같지 않습니다 .. 아무도 여기에 필요하지 않습니다.

읽고 토론합니다. Podcherppat 궁금한 점이나 제안할 점. 그리고 IDE로 끌릴 가능성은 거의 없습니다. 다른 사람들이 읽을 수 있도록 포럼에 게시하고 사용을 위해 코드가 첨부되거나 저장소에 대한 링크(또는 결합됨)가 됩니다.

그러나 이것은 추상적입니다.

 

SMA를 계산하는 함수인 Functions.py 파일에 다음 코드를 입력합니다.

import numpy as np 


def SMA(B, s, k, n, d): 
    A = B[B.size-n-s-d-k:B.size-d-k]
    Sigma = np.sum(A[n:n+s]) 
    C = np.zeros(n)
    C[n- 1 ] = Sigma   
     for q in range( 1 , n): 
        Sigma = Sigma - A[n-q+s] + A[n-q]
        C[n- 1 -q] = Sigma  
     return C/s 

시간 이동을 구현하려면 매개변수 d와 k가 필요합니다. 상관없습니다. 0으로 설정하겠습니다.

 

다음과 같은 간단한 쇠약 논리를 생각해 보겠습니다.

각 기기에 대해 판독값 사이의 z=100 간격, 즉 s=1+2*z=201 차수의 SMA로 지연되는 SMA를 계산합니다.

시장에 거래가 없거나 거래 수(특정 상품의 경우)가 허용된 수(매도의 경우 별도로, 매수의 경우 별도로)보다 작은 경우:

가격이 현재 SMA(201)보다 30핍 이상 높은 경우 - SL=TP=50핍인 매도 거래를 엽니다.

가격이 현재 SMA(201)보다 30핍 이상 낮은 경우 - SL=TP=50핍으로 매수 거래를 엽니다.

어느 시점 에서 거래의 이익 이 20핍에 도달하면 SL 또는 TP 마감을 기다리지 않고 거래를 마감합니다.

이러한 거래를 예로 들어 보겠습니다. 단순하고 어리석은 거래, 그러나 문제의 본질은 구현에 있습니다.

 

나는 거래를 개시하고 닫기 위해 다음과 같은 기능을 제공합니다:

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
사유: