Python ile Ticaret - sayfa 6

 
Алексей КоКоКо # :
Başlangıç konusunu destekleyeceğim, birçok kez hem 4 hem de 5 mql aldım ve kişisel olarak sadece ticarette bana faydalı olacak bir dil öğrenmek için çok az arzum olduğunu söyleyeceğim, ...

Eh, boşuna ya da sorunun yanlış anlaşılmasından dolayı sensin. Yine gösterge algoritmaları yazacak mısınız? Volgograd'dan Moskova'ya Vladivostok üzerinden gitmek gibi. Başka bir nüans, tüm göstergeler geçmişi hesaba katar. Onlar. Bir ay için verileri (çubukları) alırsanız, göstergeyi kendi algoritmanıza göre hesaplar ve Terminal ile karşılaştırırsanız, hesaplamalarınız farklı olacaktır.

 
Vitaly Muzichenko # :

Ben de anlamıyorum cümleyi.

Yazılanlara dayanarak, Python'u bilen büyük bir insan katmanı olduğu ortaya çıktı :) Pekala, editörü açtım ve zaten python'u biliyorum - çok basit, ama mql açtım - hiçbir şey bilmiyorsunuz.

Aynı zamanda, tamamen platform odaklı olan mql'yi "eski" bir araç olarak adlandırmak için ... python 1991'de yaratıldı ve bu çok daha erken.

Python ile yazılmış bu başlıkta gördüklerim mql'de çok basit bir şekilde uygulanıyor.

---

Hayır, olduğu gibi, konunun genel gelişimi ilginç, ama daha fazlası değil.

Üstelik - TS'nin yazdığı şey - Python'un avantajlarını hiç kullanmaz ve aslında hiç "Python tarzı" değildir. Bir tornavidayla çivi çakmak gibi, çekicin modası geçmiş

Igor Makanu # :

Lahana çorbasını höpürdetmek istiyorsanız, ancak yulaf lapası çiğnemek istiyorsanız, evinizde sadece çatal bıçak kaşıklarından şüpheleniyorum ve kullanımı oldukça güvenli.

)))

beğenin, Python kullanın, ancak konu başlatıcı olarak değil - kendi yeni özel veri türlerinizi - çubuklar, vb. oluşturmayın, kendi Mashka hesaplamanızı yazmayın... ancak hazır çözümler kullanın , aksi takdirde bu dili kullanmanın anlamı yok çünkü aynı başarı ile sinir ağları ile çalışmak için kendi paketlerinizi alıp yazabilirsiniz;)

Evet) ve bu arada, Python'da, bu tür tüccara yakın işlevlerin her türü için gerçekten bir İncil yok mu, ya da serinin tam bir istatistik analizini birkaç satırda yazabiliyorsanız, o zaman MA-shka artık gerek yok..)

 
Aleksey Mavrin # :

Evet) ve bu arada, Python'da, bu tür tüccara yakın işlevlerin her türü için gerçekten bir İncil yok mu, ya da serinin tam bir istatistik analizini birkaç satırda yazabiliyorsanız, o zaman MA-shka artık gerek yok..)

En İyi 101 Python algoritmik ticaret Kitaplıkları | PythonRepo

 

Dün foruma geri dönemedim. Devam edeceğim. Yeni bir demo hesabı açtım ve sonunda '_i' olmayan enstrümanların isimleri var, bu yüzden bu kısımdaki kodu düzelttim.

İşe yarayabilecekler için kademeli ve yavaş hareket, bir tür mikro eğitime devam edeceğim.

Bir değişken n (küçük) tanıtalım - tabiri caizse pencerenin uzunluğu olsun. Yani, fiyatları olan dosyalarda N okuma, örneğin 1000 ve n, örneğin 10 veya 100 veya 288 (zaman çerçevesi M5 ise bir gün) ayarlayalım.

Benim için d değişkeni, bu pencerenin zaman içinde geçmişe kayması anlamına geliyor. d = 0 olsun.


Örneğin, 10 kapanış fiyatı okuması ve 101 mertebesinde SMA (okumalar arasında 50 aralıklarla gecikmeli) görüntüleyeceğiz:


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 = 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']: 
         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 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)


İşin sonucu:


 

Terminali, piyasada asılı olan akım hakkında, tabiri caizse, enstrümanlarla ilgili anlaşmalar hakkında nasıl sorgulayacağımızı öğrenelim.

bir fonksiyon tanıtacağım

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)

Enstrüman için açık pozisyonların bir listesini almalarına ve bir tuple, vizha (satılacak anlaşmaların sayısı, satın alınacak anlaşmaların sayısı) döndürmelerine izin verin.

Ana işlevde, aşağıdaki parçayı terminal_done () işlevinden önce ekleyin

            # запрос открытых сделок по инструменту 
            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]))

Çalışmanın sonucu (çıktının güzelliği için n 5'e düşürüldü):


İşlemlerin fiili açılışına başlamayı öneriyorum. Tür: bazıları tarafından fiyat SMA'dan yüksekse: satışa açık, bazıları tarafından SMA'dan düşükse - satın almaya açık.

Birkaç fonksiyon daha öneriyorum: SL ve TP'nin varlığı için açık anlaşmaları kontrol etmek, eğer değillerse, kapatın ve mevcut sonucu (kar veya zarar) pip olarak döndüren bir fonksiyon.

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 
 

Emir zaten geçmişteyken ve aktif değilken durumu bir şekilde ele almayı unutmayın, ancak henüz pozisyon yok ve bu durumda tekrar açmak için emir göndermeyin.

Böyle bir durum zaman zaman meydana gelir ve örneğin Trade.mqh üzerinden çalışmak bu sorunu çözmez (en azından daha önce çözmedi - Trade.mqh'yi uzun zaman önce terk ettim).

Aynı zamanda tam tersi de olur - kapatma emri zaten geçmişte kaldı, ancak pozisyon hala görülebilir.

 
JRandomTrader # :

Emir zaten geçmişteyken ve aktif değilken durumu bir şekilde ele almayı unutmayın, ancak henüz pozisyon yok ve bu durumda tekrar açmak için emir göndermeyin.

Böyle bir durum zaman zaman meydana gelir ve örneğin Trade.mqh üzerinden çalışmak bu sorunu çözmez (en azından daha önce çözmedi - Trade.mqh'yi uzun zaman önce terk ettim).

Aynı zamanda tam tersi de olur - kapatma emri zaten geçmişte kaldı, ancak pozisyon hala görülebilir.


Açık pozisyonlar için terminalin nasıl sorgulanacağını gösterdim. Hiçbir şey kod yazmanızı engellemez, böylece pozisyon zaten varsa, isteği tekrar göndermeyin, değilse gönderin. Ayrıca, istek gönderme sonuçlarından sonra, özelliklerinde her şeyi içeren bir nesne döndürülür, normal açılıp açılmadığını veya orada hangi hatanın kayıtlı olduğunu görebilir ve bundan devam edebilirsiniz. Burada sorun yok.

 
Igor Makanu # :

En İyi 101 Python algoritmik ticaret Kitaplıkları | PythonRepo

Zaten 104) 105. burada yazıyor)

 

Şimdiye kadar TradeLogic.py dosyasının tam kodu (evet, ilkel, ancak bazılarının Metatrader 5 ve Python kullanarak ticarete kapı açabileceğinden eminim)

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)


İşin sonucu:



ZY Gösterilen en ilkel, temel kod parçaları, bence, kesinlikle herhangi bir mantığı, herhangi bir hesaplamayı, karşılaştırmayı, açık işlemlerin çeşitli kriterlere göre kontrolünü, belirli koşullar altında otomatik olarak kapatmayı, günlüğe kaydetmenin kesinlikle kolay olduğunu açıkça göstermektedir. , komut satırında olduğu gibi ve dosyalara yazma vb. vs. - herhangi bir kısıtlama olmaksızın herhangi bir şey.

ZY2 Sdelka sınıfını henüz kullanmadım ama genel olarak bu sınıfa ait nesneleri fonksiyonlara geçirmek, .json olarak dosyalara yazmak vs. uygun oluyor - ama nedense biraz yorgunum, isteyenler olur diye düşünüyorum. Anladım, burada bir konuda yardımcı olabilirim. İstenirse, grafik arayüzü vidalayabilirsiniz.


Herkese Python + metatrader5 kitaplığı ile ticaret yapmayı şiddetle tavsiye ederim.

 
Mikhael1983 # :

Açık pozisyonlar için terminalin nasıl sorgulanacağını gösterdim. Hiçbir şey kod yazmanızı engellemez, böylece pozisyon zaten varsa, isteği tekrar göndermeyin, değilse gönderin. Ayrıca, istek gönderme sonuçlarından sonra, özelliklerinde her şeyi içeren bir nesne döndürülür, normal açılıp açılmadığını veya orada hangi hatanın kayıtlı olduğunu görebilir ve bundan devam edebilirsiniz. Burada sorun yok.

Bir kez daha: sipariş zaten dolduruldu ve tarihe geçti. Artık aktif değil. Pozisyon zaten açık, ancak henüz görünmüyor, istek onu göstermiyor.

Genellikle bu çok kısa bir zaman aralığıdır ve özellikle her zaman gerçekleşmediği için buna ulaşmak zordur.

Ancak örneğin bir sabah açıklığı ve büyük bir sipariş akışı ile bu durum saniyeler değil dakikalar sürebiliyor.

Daha açık olmak gerekirse: TRADE_TRANSACTION_ORDER_DELETE, TRADE_TRANSACTION_HISTORY_ADD veya TRADE_TRANSACTION_DEAL_ADD'den önce geldi

Ve bir noktada, ne aktif olanlarda ne de tarihte emirleri göremeyebiliriz veya bir emir veya anlaşma görmeyebiliriz.

Neden: