Python ile Ticaret - sayfa 4

 
Malik Arykov # :

Python'un MT5 ile entegrasyonu tamamlanmadı demek istiyorum. Gösterge değerlerini DOĞRUDAN alamazsınız

Verileri mql olarak kaydetme
 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);

Python'da veri okuma

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 # :

Konunun amaçları beş sent kadar basittir: herkesin terminal ile iletişimi başlatmak, fiyat teklifi istemek, sunucudan bir işlemi açmasını veya kapatmasını istemek gibi kod parçalarını basitçe kopyalayarak Python'da algoritmik ticarete başlamasına izin vermek. vb. Üstelik bunun için son derece uygun bir dilde sadece mantığa odaklanın.

peki, evet ... mantık algoritmik ticaret için yeterli değil - "herkes" kod parçalarını eklemeden ve gerçek ticarete tırmanmadan önce bir ticaret stratejisini test etmeniz gereken mantık


neyse, "efsanevi olmayan" hedeflerinde iyi şanslar

)))

 

Fiyatların dosyalara kaydedilmesine ihtiyaç duymayan kişiler, kodu hafifçe yeniden yazacak ve "dosyalara yaz - dosyalardan oku" değil, sadece hemen ihtiyaç duydukları veri yapısını yapacaktır. Burada, birçok yönden, ilk adımları atmak isteyenler için sadece ilkel şeylerin bir görüntüsü.

Ancak, listeler, demetler, sözlükler vb. gibi kavramlara zaten aşina olanlar.

Fiyat dosyalarından read_all_files_with_prices işlevini kullanarak okumanızı öneririm; bu işlev, her bir simge için fiyatların bulunduğu dosyayı okumak için read_file_with_prices işlevini kullanır.

read_file_with_prices işlevinin , orijinal fiyat dosyasına karşılık gelen satırları ve sütunları olan bir numpy.ndarray dizisi (fiyatlar başarıyla okunduysa ve veri bütünlüğü denetiminden geçtiyse, her öğenin türü numpy.float64'tür) veya ' dizesi döndürsün. veri yok 'veriler okunmadıysa veya eksikse.

read_all_files_with_prices işlevinin tüm araçlar için tırnak işaretleri içeren bir sözlük döndürmesine izin verin. Bu sözlükteki anahtarlar, araçların adları, değerler - karşılık gelen bir enstrüman için tırnak işaretleri olan sözlükler olsun. Bir enstrüman için tırnak içeren sözlüklerde, anahtarlar tarih-saat okumalarıdır (tarih_saat sınıfı), değerler çubuklardır (çubuk sınıfı), ayrıca anahtar sağlamayı öneriyorum:

  • 'is_data': anahtara göre değer - Tırnak işaretleri varsa doğru, Yanlış - dosyadan okuma işlevi 'veri yok' döndürdüyse,

  • 'enstrüman': anahtara göre değer - araç (str);

  • 'prices': anahtara göre değer - araç fiyatları dizisi (numpy.ndarray)

Kısacası, böyle bir veri yapısı öneriyorum:


 

Python kodu en iyi şekilde IDE/editör/web sitesinden ekran görüntüleri olarak yerleştirilir.

en azından kod yorumlarının yerel olarak vurgulanmaması, onu okunamaz hale getirir, ana metinle birleşir.

 

Dosyaları okumak ve yukarıdaki veri yapısını oluşturmak için fonksiyonlar eklendi:

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 kodu en iyi şekilde IDE/editör/web sitesinden ekran görüntüleri olarak yerleştirilir.

en azından kod yorumlarının yerel olarak vurgulanmaması, onu okunamaz hale getirir, ana metinle birleşir.

Ancak onu kopyalayabilir ve IDE'de açabilirsiniz ve resimden manuel olarak yeniden yazabilirsiniz, belki ...


Yukarıdaki program nasıl çalışır:



Prensip olarak, verileri analiz etmeye, ticaret kararları vermeye ve uygulamaya başlamak için hemen hemen her şey hazırdır.

 
Mikhael1983 # :

Ancak onu kopyalayabilir ve IDE'de açabilirsiniz ve resimden manuel olarak yeniden yazabilirsiniz, belki ...


kimsenin kodu kopyala-yapıştır ile uğraşması pek olası değildir .. burada kimsenin buna ihtiyacı yok

okuyun ve tartışın. Meraklı bir şey ya da önerecek bir şey Podcherppat. Ve IDE'ye sürüklenmesi pek olası değildir. Başkalarının okuması için forumda yayınlarlar ve kullanım için kod ya eklenir ya da havuza bir bağlantı (veya birleştirilir)

ama bu soyut.

 

Aşağıdaki kodu, SMA'yı hesaplayan bir işlev olan Functions.py dosyasına koyun.

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 

Zaman kaymasını uygulamak için d ve k parametrelerine ihtiyacım var, önemli değil, onları sıfıra eşitleyeceğiz.

 

Basit bir sakatlık mantığı ile geleceğim, örneğin:

her enstrüman için, okumalar arasındaki z=100 aralıkla SMA gecikmesini hesaplıyoruz, yani s=1+2*z=201 düzeyindeki SMA.

Piyasada işlem yoksa veya bunların sayısı (belirli bir enstrüman için) izin verilen sayıdan azsa (Satış için ayrı, Alım için ayrı ayrı), o zaman:

fiyat şu anda 30 veya daha fazla pip ile SMA(201)'den yüksekse - SL=TP=50 pip ile bir satış işlemi açın,

fiyat şu anda 30 veya daha fazla pip ile SMA(201) altındaysa - SL=TP=50 pip ile bir alım satımı açın.

Bir noktada anlaşmanın karı 20 pip'e ulaşırsa, SL veya TP'nin kapanmasını beklemeden kapatın.

Örnek olarak böyle bir ticareti uygulayalım. Ticaret açısından basit, aptalca, ancak meselenin özü uygulamada.

 

İşlemleri açmak ve kapatmak için aşağıdaki işlevleri sunuyorum:

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
Neden: