AOS v Pythonu jednoduše, snadno a rychle

pythonMožná jste zaregistrovali, že od března poskytuje IB nativní API pro Python. Hurá, sláva, jde v tom programovat AOS. Jenže i API pro Python funguje stejně jako API pro JAVu, C# a C – asynchronně. Váš program zavolá nějakou funkci, ta pošle dotaz (request) do TWS a za nějakou dobu TWS vrátí nějaký výsledek zpátky. Program si musí pamatovat číslo requestu a v nějaké návratové funkci si odlovit výsledek. Nebo když se někde něco nepovede, v jiné funkci by se mělo odlovit chybové hlášení. Pro začátečníka celkem složité programování.

IB_INSYNC

Nedávno jsem ale narazil na úplně geniální knihovnu, která používá nativní API, ale použití značně zjednodušuje. Je to modul ib_insync a stránky projektu jsou zde:

https://github.com/erdewit/ib_insync

Dokumentaci si lze prohlédnout tady:

http://rawgit.com/erdewit/ib_insync/master/docs/html/notebooks.html

V čem je ta knihovna tak geniální? Jednoduše v tom, že spoustu věcí ošetří za mě a já už se nemusím starat o čísla requestů. Navíc spoustu věcí lze poslat synchronně – zavolám funkci a ona mi vrátí výsledek. Dost teoretizování, pojďme si to ukázat.

Pozor. Pokud budete chtít zde uvedené příklady vyzkoušet, tak zkoušejte při otevřeném DEMO ÚČTU! Jinak se příkazy provedou a Vy skončíte s akciemi na ostrém účtu.

Příklady použití

Následující program vypíše obchodní časy pro burzu NYSE na následujících 30 dní:

from ib_insync import *
ib = IB()  
ib.connect('127.0.0.1', 7497, 17)  

contract = Stock('GE', 'NYSE', 'USD')
[cd] = ib.reqContractDetails(contract)

list = cd.tradingHours.split(';')
for item in list:
    date, openingHours = item.split(':')
    print(date,openingHours)

To je celé. Když program spustíte, dostanete výsledek:

20171208 0930-1600

20171209 CLOSED

20171210 CLOSED

20171211 0930-1600

20171212 0930-1600

atd.

Jak program funguje?

ib = IB() je základní objekt, přes který se všechno volá

ib.connect(‚127.0.0.1‘, 7497, 10) se připojí k TWS (Trader Workstation), která běží na lokálním počítači (ten má adresu 127.0.0.1). Chci-li připojit náš skript k IB gateway, změním číslo portu na 4001 (to je výchozí port pro naslouchání v IB Gateway). 10 je jen číslo klienta, kdybych se náhodou k TWS připojil z několika programů najednou, aby to TWS odlišila.

 

Stock() je funkce z té geniální knihovny, která vrátí objekt typu contract, který očekává TWS, když po ní něco chci. Kromě Stock() to umí i další jiné věci, např.:

Stock('AMD', 'SMART', 'USD')
Stock('INTC', 'SMART', 'USD', primaryExchange='NASDAQ')
Forex('EURUSD')
CFD('IBUS30')
Future('ES', '20180921', 'GLOBEX')
Option('SPY', '20170721', 240, 'C', 'SMART')
Bond(secIdType='ISIN', secId='US03076KAA60')

Největší kouzlo ale spočívá v řádku:

[cd] = ib.reqContractDetails(contract)

Funkce se jmenuje stejně jako v TWS API, ale pozor, tady voláme uživatelsky přívětivější funkci z knihovny ib_insync, která je synchronní – blokuje další program, dokud nedostane od TWS odpověď. Program se zastaví a čeká, až TWS odpoví a pak uloží odpovědi do proměnné cd. Ty hranaté závorky tam jsou pro to, že funkce může vrátit několik objektů a vrátí je jako list objektů (list je v pythonu označení pro pole). Kromě blokující varianty v knihovně je i neblokující, asynchronní funkce reqContractDetailsAsync, která se chová stejně jako funkce v nativním API, takže když bychom chtěli posílat dotazy asynchronně, můžeme to dělat i prostřednictvím této knihovny.

Objekt contractDetail má spoustu atributů a mezi nimi je atribut tradinghours ve formátu textového řetězce, kde jsou jednotlivé dny oddělené středníkem. Zbytek programu už jen vezme tenhle řetězec a rozseká ho na jednotlivé dny a vypíše.

Další příklad – historická data

from ib_insync import *
ib = IB()
ib.connect('127.0.0.1', 7497, clientId=1)
contract = Forex('EURUSD')
bars = ib.reqHistoricalData(contract, endDateTime='', durationStr='30 D',
        barSizeSetting='1 hour', whatToShow='MIDPOINT', useRTH=True)
# convert to pandas dataframe:
df = util.df(bars)
print(df[['date', 'open', 'high', 'low', 'close']])

Program vypíše:

date open high low close

0 2017-10-29 22:15:00 1.161300 1.161475 1.160525 1.160600

1 2017-10-29 23:00:00 1.160600 1.160625 1.159375 1.159475

2 2017-10-30 00:00:00 1.159475 1.161000 1.159475 1.160575

atd.

Program je opět jednoduchý, zavoláme ib.reqHistoricalData() s potřebnými parametry a ta počká, až TWS vrátí data. Předposlední řádek zkonvertuje výsledky do tabulky ve formátu pandas.dataframe, což je jiná geniální knihovna pro práci s tabulkami hodnot.

Teď něco složitějšího – chci poslat několik příkazů k nákupu a pak chci počkat, až se všechny vyplní:

from ib_insync import *
import sys
ib = IB()
ib.connect('127.0.0.1', 7497, clientId=1)
symbols = ['GE', 'IBM', 'AAPL']
trades = {}

# pro každý kontrakt pošli buy order
for symbol in symbols:
    contract = Stock(symbol, 'SMART', 'USD')
    ib.qualifyContracts(contract)
    order = MarketOrder('BUY', 1)
    trades[symbol] = ib.placeOrder(contract, order)

# počkej dokud všechny ordery nejsou ve stavu finished
isPendingOrder = True
i = 0
while isPendingOrder:
    i += 1
    ib.sleep(0.1)
    isPendingOrder = False
    for symbol in trades:
        if trades[symbol].isActive():
              isPendingOrder = True
              break
    if i > 50:
        print("Waiting for orders filling Timeout! Check orders manually")
        ib.disconnect()
        sys.exit(1)

# vypiš kusy a ceny
for symbol in symbols:
    filled = trades[symbol].orderStatus.filled
    fillPrice = trades[symbol].orderStatus.avgFillPrice
    print( symbol, 'Filled:', filled, 'AvgPrice:', fillPrice)
# ukázka trades objektu
for symbol in symbols:
    print(trades[symbol])

výsledek

GE Filled: 1.0 AvgPrice: 17.74

IBM Filled: 1.0 AvgPrice: 154.84

AAPL Filled: 1.0 AvgPrice: 169.27

Program si na začátku uloží 3 tickery do listu a pro každý ticker pak pošle order.

ib.qualifyContracts() doplní do kontraktu hodnoty, které TWS potřebuje pro to, aby mohla poslat order.

MarketOrder() je něco jako Stock() pomůže nám nadefinovat parametry příkazu k nákupu. Mohl by to být třeba LimitOrder() nebo jiný typ příkazu.

ib.placeOrder(contract, order) pošle do TWS příkaz k nákupu a vrátí objekt typu trade, který bude mít status active. Tentokrát to není blokující funkce, program poběží dál. Objekt typu trade bude prázdný, ale až se obchod provede, tak se naplní údaji. Objekt si jen ukládám do Pythonovského pole trades[symbol], přes který se dobře iteruje. (Kdo nezná python, tak trades[‚GE‘] vrátí objekt pro GE, trades[‚IBM‘] pro IBM, atd.)

Trade objekt pro ‚AAPL‘ vypadá takhle:

Trade(contract=Stock(conId=265598, symbol='AAPL', exchange='SMART', 
primaryExchange='NASDAQ', currency='USD', localSymbol='AAPL', tradingClass='NMS'), 
order=MarketOrder(orderId=49, action='BUY', totalQuantity=1), 
orderStatus=OrderStatus(status='Filled', filled=1.0, avgFillPrice=169.27, 
permId=854930875, lastFillPrice=169.27, clientId=1), 
fills=[Fill(contract=Stock(conId=265598, symbol='AAPL', exchange='SMART', 
primaryExchange='NASDAQ', 
currency='USD', localSymbol='AAPL', tradingClass='NMS'), 
execution=Execution(execId='00018037.5a2abcdf.01.01', time='20171208 20:32:06', acctNumber='XX999999', 
exchange='ISLAND', side='BOT', shares=1.0, price=169.27, permId=854930875, clientId=1, orderId=49, 
cumQty=1.0, avgPrice=169.27), commissionReport=CommissionReport(), 
time=datetime.datetime(2017, 12, 8, 19, 32, 30, 995578, tzinfo=datetime.timezone.utc))], 
log=[TradeLogEntry(time=datetime.datetime(2017, 12, 8, 19, 32, 30, 845558, 
tzinfo=datetime.timezone.utc), status='PendingSubmit', message=''), 
TradeLogEntry(time=datetime.datetime(2017, 12, 8, 19, 32, 30, 995578, 
tzinfo=datetime.timezone.utc), status='PendingSubmit', message='Fill 1.0@169.27'), 
TradeLogEntry(time=datetime.datetime(2017, 12, 8, 19, 32, 30, 996078, tzinfo=datetime.timezone.utc), status='Filled', message='')])

Poté, co se odeslaly všechny objednávky chci počkat na to, až se všechny vyplní. To zajistí smyčka while , která běží stále dokola dokud existuje alespoň jeden trade ve stavu active. Důležité je, že ve smyčce je příkaz ib.sleep(0.1), který počká 0.1 sekundy. Tenhle příkaz je součástí knihovny ib_insync a je napsaný tak, že knihovna během něj provede aktualizaci údajů v objektech typu trade. Kdyby ve smyčce tento příkaz nebyl a byl tam třeba “normální” procesorový sleep(0.1), zabrala by si smyčka pro sebe veškerý čas procesoru a knihovna by nezaktualizovala údaje o obchodech, které dostaly plnění. Pro jistotu je ve smyčce počítadlo a pokud se všechny objednávky nevyplní do 50ti průchodů neboli do 5ti sekund, tak to ukončí program s chybou.

Knihovna podporuje většinu funkcí, které má nativní API, takže se dá využít třeba i ke čtení market cen, zjišťování otevřených pozic a stavu na účtu, atd.

Tuhle knihovnu ocení asi hlavně začátečníci. Ten kdo už má v Pythonu nebo jiném jazyce napsaný AOS přes IB API, tak si asi víceméně napsal potřebné funkce sám, ale třeba když budete chtít vyzkoušet nějakou funkci, kterou IB API má, můžete si pomocí téhle knihovny spíchnout rychlý skriptík.

Nevýhodou samozřejmě je, že spoléháte na knihovnu, kterou vytvořil někdo jiný a že ten někdo bude tu knihovnu i v budoucnu udržovat a aktualizovat. Na druhou stranu knihovna je open source, takže je dobrá šance, že najde někdo, kdo v nejhorším celý projekt převezme. Tvůrce si pravděpodobně na knihovně postavil vlastní AOS a tím že jí dal k používání, tak si tím nechává zdarma testovat a ladit chyby. Takže by to mohlo nějakou dobu vydržet.

Pozn.: Autorem článku je trader a zde diskutující človíček s přezdívkou Myk.

Příspěvek byl publikován v rubrice Nezařazené. Můžete si uložit jeho odkaz mezi své oblíbené záložky.

61 komentářů u AOS v Pythonu jednoduše, snadno a rychle

  1. krokr napsal:

    Něco podobného se základními funkcemi mám napsáno pro C#. Zároveň jsem si API přepsal, abych nepracoval s double, ale s decimal datovým typem. Možná by to zdejší komunita ocenila. Jakmile se k tomu dostanu, mám v plánu to dát na github.

    • admin napsal:

      Já jako .NET člověk bych to určitě ocenil.

      • master napsal:

        https://github.com/mastercs999/ib-api-sync

        Udelal jsem si to pro svoje pouziti a tam mi to funguje bezchybne. Jestli to budu dal rozsirovat, to zalezi jestli bude mit nekdo zajem :D

        • nemozny napsal:

          Krásná práce! Je v tom vidět ruka profesionála.

          Jen jsem speciálně koukal na ten
          public static bool IsLastStatus(this OrderStatus orderStatus)
          {
          return orderStatus == OrderStatus.Filled || orderStatus == OrderStatus.Cancelled || orderStatus == OrderStatus.Inactive;
          }

          Já jsem musel přidat i „submitted“ a snad i „presubmitted“, protože dělám bracket ordery (MKT + STP) a ten STP se nevyplní.

          Nebo ty PlacedOrdery rozlišovat by bylo vhodné, mě tak napadá..
          Závidím ten multithreading.

        • admin napsal:

          No, master, tohle je z technologického hlediska asi nejšlechetnější počin, co jsem tady na winpes zaznamenal. Tleskám a rozhodně to vyzkouším. Myslím, že o tohle bude zájem 100%ně. I ve světě.

          Vždyť se podívej na úrveň API, co dodává IB samotné. To chce wrapper jako sůl.

  2. Jelimán napsal:

    za mě super, díky Mykovi

  3. Duke napsal:

    Skvělé, asi se vrátím k programování. Python je pro mě volba číslo 1.

  4. nemozny napsal:

    Nice!
    Už jsem skoro překonal svou nenávist k Pythonu a začal skoro litovat, že jsem psal AOS v Node.
    Nicméně hlavním důvodem by určitě nebyla tahle knihovna ale pandas a NumPy.

    • admin napsal:

      no, obecně v IB API je problém cokoliv udělat synchronně (například realizovat jednu objednávku a potom další, pokud ta první prošla). Pokud to tahle knihovna umí (nezkoušel jsem to v praxi), tak to otevírá nové možnosti.

      protože ty nadstavby co znám se chovají stylem „pošli dotaz a my Ti někdy nějak odpovíme“ a jsou tedy asynchronní.

      • myk napsal:

        Umí to synchronně číst historická data, contractDetails apod.

        Market data např. čtu tak, že pošlu dotazy reqMktData a nestarám se o requesty ani o to, co se kde vrátilo. Někde v paměti mám tabulku, která se postupně aktulizuje o údaje, jak je vrací TWS. Takže ve smyčce čekám, dokud všechny symboly v tabulce nedostanou vyplněnou hodnotu close.

        No a posílání orderů má názorný příklad přímo v článku. Není to přímo synchronní, protože chci odpálit víc příkazů najednou a ne čekat až se jeden vyplní a pak poslat druhý. Takže příkazy odpálím a pak zase mám někde v paměti tabulku příkazů, které mi někde na pozadí aktualizuje ta knihovna (o to se nemusím vůbec starat) a já si ve smyččce počkám si, dokud všechny příkazy nemají status filled.

        • nemozny napsal:

          To je pěkná věc, ale myslím si, že takto si stejně musí každý postavit svou logiku na IB API, aby to dávalo alespoň trochu smysl.
          Trochu mě tam děsí

          while isPendingOrder:
          i += 1
          ib.sleep(0.1)
          isPendingOrder = False

          Osobně se snažím vyhnout těmto praktikám, jako sleep a setTimeout atp. obecně všemu, co pauzuje exekuci. Od toho jsou asynchronní knihovny.

          Já dělám:
          placeOrder() { čekej na vyplnění asychronní Promise z funkce waitForOrders() }

          waitForOrders() { všechny ordery jsou Filled nebo Submitted nebo Failed -> resolve Promise a vrať se do placeOrder()
          jestliže dosud nejsou všechny ordery vyplněny, spusť reqOpenOrders() a opakuj pořád dokola }

          Dívám se, že Python od verze 3.5 také umí async/await, to si myslím je nejelegantnější řešení async volání.

          • nemozny napsal:

            Nojo, jasně, ib_insync je postavena na async/await.

            • myk napsal:

              Ten sleep(0.1) je moje konstrukce a asi není optimální.

              Doporučené v examplech je např.
              while not trade.isDone():
              ib.waitOnUpdate()

              Jenže to jsem zavrhnul, protože 90tka se obchoduje před koncem a pokud by order nedostal fill a stoply se data, tak už nepřijde od TWS update a mohlo by to čekat věčně. Tak jsem si napsal vlastní smyčku s pomocí ib.sleep(), která timeoutuje. Desetina vteřiny mě nezabije, když jsem zkušebně poslal třeba 5 orderů, tak jsem na fill čekal stejně několik cyklů.

              Asi se to dá napsat elegantněji pomocí knihovny asyncio, ale já jsem bývalý ETL/database developer, informatiku jsem nestudoval, takže tyhle asynchronní věci jsem viděl poprvé před měsícem a přiznávám, že to zatím neumím používat. Takže ta knihovna je pro mě docela spása.

              • admin napsal:

                Optimální ta konstrukce možná není, ale určitě to elegantně řeší nějaké problémy, které IB API vytváří. Protože, jak všichni víme, IB API psali lidi, co měli na hulení hodně kvalitní matroš ;-)

    • myk napsal:

      Je jasné, že bývá nejlepší prgat v tom, co člověk aktivně používá. Nicméně pro začátečníky nebo jako pro mě, pro programátory v důchodu, může být Python dobrá volba. Z jazyků, které nabízí API bych to začátečníkům doporučil, určitě lepší než začínat z nuly s Javou nebo C++. C# může být též volba.

      Jinak pandas je opravdu geniální knihovna, používám jí jak na backtest tak i na AOS, a to v kombinaci s xarray knihovnou, která zjednodušuje práci s multidimenzionální tabulkou.

      Příklad:
      import xarray as xr
      import pandas as pd
      # načti data z csv souborů do dictionary of pandas dataframes
      dfDict = {}
      for symbol in SP100Symbols:
      FileName = Path + symbol+‘.csv‘
      dfdict[symbol] = pd.read_csv(FileName, index_col=0)

      #přidej do dataframes indikátory:
      for symbol in panel_dict:
      panel_dict[symbol][‚SMA200‘] = panel_dict[symbol][DATA_COL].rolling(200, center=False).mean()
      panel_dict[symbol][‚SMA5‘] = panel_dict[symbol][DATA_COL].rolling(5, center=False).mean()
      panel_dict[symbol][‚RSI2‘] = funcRSI(panel_dict[symbol], column=DATA_COL, period=2)

      # převeď dictionary of dataframes na xarray
      xr_panel = xr.Dataset(panel_dict)

      # udělej časový řez pro dnešek
      now = pd.Timestamp(datetime.datetime.now())
      now_str = str(now.year) + ‚-‚ + str(now.month).zfill(2) + ‚-‚ + str(now.day).zfill(2)
      ds_xr = xr_panel.sel(dim_0 = now_str)
      # zkonvertuj zpátky na dataframe
      ds = ds_xr.to_dataframe()

      A ds obsahuje dnešní řez: pro všechny symboly mám dnešní close, SMA200, SMA5 s RSI2. A pak už stačí jen trocha magie:
      dsn = ds.transpose()
      candidates = dsn[dsn[‚Adj Close‘]>dsn[‚SMA200‘]]
      candidates = candidates[candidates[‚RSI2‘] < 10.0 ]
      candidates = candidates.sort_values(by = 'RSI2', ascending=True)

      A tabulka candidates obsahuje všechny kandidáty na otevření pozice setříděné podle RSI2

      • admin napsal:

        K tomu data například z alphavantage a systém je hotov ;-)

        • Balu napsal:

          Jsem tu nový, takže v první řadě všechny zdravím a děkuji za tento skvělý web!
          Zatím si jen hraji a můj setup je – Windows, Python, MariaDB, IB Gateway(paper account).

          Ono ten příklad s načítáním z CSV souboru přímo nabádá k využívání dat z AlphaVantage, který exportuje do CSV nebo JSON.
          Bohužel export dat z AlphaVantage je příšerně pomalý.
          Compact data nestačí pro SMA200, takže se člověk musí zaměřit na Full export a v tom případě se mi data exportují rychlostí 3-4 Tickery za minutu.
          Jako šlo by to ještě upravit na dvojité načítání – nejdřív Full někdy během dne a pak Compact jen pro dnešní den pro výpočet algo.
          Ale i v Compact verzi se s 99 Tickery dostávám k 3 minutám :(

          Pokud tahám data z IB (zatím jen delayed v rámci paper accountu) tak mám market price pro těch 99 tickerů za cca 4 vteřiny.

          Yahoo a Google financial API jsem zavrhl, protože v jejich současném stavu jim nevěřím a prověřené wrappery přestaly fungovat.

          Doba je zlá pro nováčka, který se chce dostat k bezplatným a důveryhodným datům pro vývoj a testování :)

          • admin napsal:

            … a proto chceš quandl!

            • myk napsal:

              jj, používám quandl

              data = quandl.get(„WIKI/“ + symbol, start_date=startDate, end_date=endDate, api_key=“XXXXXXXX“)

              Komplet historická data jsou stažena asi za minutu, akorát se mi párkrát stalo, že byly asi dva dny, kdy to padalo na nějakou náhodnou chybu. Takže když to spadne, tak to zkusím spustit ještě jednou, případně ještě jednou a pak už to projede.

              • nemozny napsal:

                Já zase zavrhl Quandl, protože zdroje tohoto typu mají vždy nějaká omezení.
                Akcie z Yahoo – https://query2.finance.yahoo.com/v8/finance/chart/0003.HK?period1=1337378400&period2=1495144800&interval=1d
                Futures z Barchart – https://www.barchart.com/proxies/timeseries/queryeod.ashx?data=daily&maxrecords=960&volume=contract&order=asc&dividends=false&backAdjust=false&symbol=gcf17
                obojí v JSON a nemusím se na nikoho spoléhat. Yahoo není úplně 100%, ale na paper provoz stačí.

                • myk napsal:

                  No zrovna yahoo letos v květnu bez varování změnilo url, a všem to přestalo běhat, ne?
                  Ten Quandl vydává svoje knihovny pro různý jazyky, takže se dá předpokládat, že na změnu připraví update knihoven a ne že to vypadne z ničeho nic.

                  • nemozny napsal:

                    No ale tak změna URL je jen změna URL.
                    Ne, jasně, pokud dáváte přednost knihovně, tak je to bez diskuzí.
                    Já tím jen chtěl říct, že se nemusím na nikoho spoléhat.

                    • Honza napsal:

                      Rekl bych, ze s tim yahoo to bylo trochu jinak – Oni zrusili stary endpoint, ktery nevyzadoval autentifikaci a zbyl tam ten jeden – query2.finance.yahoo.com, z ktereho se nacitaji data na web. Ten uz vyzaduje autentizaci pomoci nejakeho tokenu co se uklada do cookies pri nacteni stranky yahoo finance, takze je potreba resit vic nez jen zmenu URL.

                      Pokud bych si mel vybrat mezi resenim tohodle a ostatnich problemu o samote nebo s lidmi, kteri maji stejne zajmy, tak volim to druhe.

                    • nemozny napsal:

                      Promiň Honzo, ale zkoušel si kliknout na URL? Našel jsi tam nějakou autentizaci?

                    • Honza napsal:

                      Ahoj, ja se omlouvam. Bral jsem to tak, ze kliknuti na odkaz nic neznamena, protoze session token je ulozeny v cookies, ktere ty nevidis. Zkusil jsem si data fetchnout pres wget a pak i jednoduchy script v nodu a funguje to, takze mas pravdu.

                      Kazdopadne zmeny co jsem psal se resily na tomhle modulu https://github.com/pilwon/node-yahoo-finance/pull/37 pres ktery jsem tahal data z yahoo (to ze to ted jde i bez autentizace je asi nepotesi)

                      A stale se drzim toho, ze open source a prace ve vice lidech je lepsi nez resit si vsechno sam. Kazdopadne jednou sorry za neporadnost, dam si ted povinne 4 dny odpocinku a pak teprve zacnu neco komentovat.

                    • nemozny napsal:

                      Není třeba se omlouvat, já ten thread sledoval také a nechápal jsem, co tam ti borci vyvádí.
                      Evidentně zbytečnosti.
                      Jinak by možná stačil i ten barchart na všechno, nevím.
                      Jsou skvělí, ale barchart on-demand je celkem drahý.

                • admin napsal:

                  Jaké omezení má QUANDL? Mě přijde sympatický…

                  https://www.quandl.com/about

                  • VM napsal:

                    Bohužel za poslední rok se už 2x stalo, že v té jejich EOD free databázi chybí celý den. Naposledy tak před 2 měsíci. Když to ani po týdnu nikdo neopravil, přestal jsem to používat :(

                    Teď koukám na https://iextrading.com, je to zdroj dat pro AlphaVantage a je to free. Nechcete to někdo prozkoumat? ;)

                    • admin napsal:

                      To jsem neznal, prozkoumám, dík

                    • myk napsal:

                      Dobrý tip.
                      Market data pro všechny SP100 symboly mi to vrací za 4,8 sekundy, což je o něco pomalejší než TWS.
                      Čtení 1year EOD dat pro všechny SP100 akcie mi trvá cca 2 minuty.

                    • admin napsal:

                      Ano, čtení dat pro 100 tickerů dělá u mě v PHP cca 2 minuty a něco, v nouzi by to pomoct mohlo.

                      Nicméně, nechápu, proč neudělají něco jako více dat více tickerů v jednom requestu, to jsme jediný, kdo by to ocenil?

                      Zkusím v nějakém jazyce co to podporuje požadavky na stažení dat paralelizovat, PHP na toto není moc dobrý nápad, otestuju .NET a dám vědět jak jsem dopadl.

                    • Balu napsal:

                      v Pythonu mám 1y dat pro SP100 za 1 minutu a 27 vteřin i s uložením do databáze.

                      Hromadný dowload by měl jít přes:
                      https://api.iextrading.com/1.0/stock/market/batch?symbols=aapl,fb,tsla&types=chart&range=1y
                      Ale je potřeba si to parsovat, protože u tohoto requestu nefunguje parametr ‚csv‘.

                    • myk napsal:

                      Kdo chce tahat data z iextrading.com v Pythonu, tak tady je hotová knihovna i s návodem. Data vrací rovnou v pandas dataframe:
                      http://www.enlistq.com/python-api-getting-market-financial-data-iex/

                      stažení 1y historie pro celý SP100 najednou:
                      sp100 = [‚APPLE‘, ‚CSCO‘, ….]
                      bars = iex.get_trade_bars_data(sp100, bucket=’1m‘)

                    • Balu napsal:

                      Děkuji, na tu knihovnu jsem také narazil, ale snažím se mít vlastní kus kódu, který mám pod kontrolou, pokud je to jen trochu možné.

                      Zde jednoduchá fce pro 1y historii pro jeden symbol.
                      Vrací také pandas dataframe.

                      def get_EOD_prices(symbol):
                      payload = {
                      „format“: „csv“
                      }
                      endpoint = „stock/“ + symbol + „/chart/1y“

                      raw = requests.get(base + endpoint, params=payload)
                      raw = io.BytesIO(raw.content)
                      prices_df = pd.read_csv(raw, sep=“,“)

                      return prices_df

                    • nemozny napsal:

                      Jasně, to je ale IEX. Není to provider dat, ale „fair, simple, and transparent stock exchange“. Opět viz Michael Lewis – Flash boys.

                  • Balu napsal:

                    QUANDL jsem definitivně zavrhl.
                    Mimo to, že mu chybí data pro některé obchodní dny, tak si je na druhou stranu schopen „vymyslet“ data pro burzovní prázdniny(na konec linku si doplňte váš klíč):
                    https://www.quandl.com/api/v3/datatables/WIKI/PRICES.json?date=20170414&ticker=LOW&api_key=

              • Balu napsal:

                Díky za nasměrování na Quandl. Ta rychlost je o moc lepší.
                Quandl ale vrací jen historická data, kdežto AlphaVantage vracel i poslední market price pro dnešní den.

                Takže teď zas pro změnu hledám nezpožděný zdroj intraday dat pro získání market price v době spuštění algoritmu.

                Ono nakonec to vypadá, že jen s paper accountem u IB celý AOS nenasimuluji, aby dával reálné výsledky. Bude to asi chtít investici do subscripce market dat od IB. Pak už mi vychází jako smysluplné jet jen na datech od IB – historie i aktuální market price.

                Obecně mám jednu možná trochu hloupu otázku.
                SMA200 a SMA5 se počítá pouze na historických datech?
                RSI2 na historických(13 dní) + aktální market price v době spuštění algoritmu(těsně před uzavřením burzy)?
                Výpočty ukazatelů jako takových mi problémy nedělají.

                • myk napsal:

                  Zapni NYSE+NASDAQ za 3USD na měsíc, to je přijatelná cena.
                  Já to počítám všechno včetně aktuální ceny. Můžeš to počítat i jinak, pokud si to zbacktestuješ a bude to dávat solidní výsledky. Adminův setup je jen jeden z možných, ale dá se to upravit různě.

                  • Richard napsal:

                    Myk pls a pri NYSE+NASDAQ za 3USD sa daju z IB stiahnut vsetky hist data pre 90tku? Resp stale je tam to obmedzenie ze to treba delit a riesit tam delay?
                    Dik

                  • admin napsal:

                    Ano, je to jen nástřel. Jinak pro výpočet VŠECH indikátorů vč. SMA5 a RSI2 používám všechna data VČETNĚ dnešních. Vtip je ale v tom, že ze zdrojů dat, co tady diskutujeme ta datazískáš na jeden, max. dva dotazy, kdežto u IB budeš muset tahat historická data a spoléhat na to, že Ti dostatečně rychle dotečou. A pak začneš řešit splity … a pacing violation … a pak pochopíš.

                    • myk napsal:

                      Historická data nejsou bottleneck, já si je tahám odpoledne a ukládám do souborů. Pro běh 90tky si pak jen načtu připravená data.

          • master napsal:

            Jen upozorním na novou feature alphavantage – stažení aktuálních cen až pro 100 tickerů najednou: https://www.alphavantage.co/documentation/#batchquotes

      • nemozny napsal:

        Super!
        Až bude víc času, také bych chtěl u sebe přepsat logiku okolo datových řad do dataframes, protože iterace přes arrays jsou neskutečný opruz.
        Jenom v případě obecně data science je nejdůležitější důkladná kontrola a normalizace dat ve smyslu souvislých (bez mezer) a správných (validních údajů) dat v dataframu. To jen tak, kdyby si s tím někdo hrál…
        A pandas s pyplot je už úplná fantazie (https://plot.ly/python/ipython-notebook-tutorial/)

  5. myk napsal:

    chybička se vloudila, chtěl jsem nahradit panel_dict kratším dfDict, aleneudělal jsem to všude.

  6. Balu napsal:

    Bezi vam nekomu testovaci AOS s python knihovnou IB_INSYNC na paper accountu u IB? Pokud ano, jak dlouho vam trva exekuce prikazu u IB? Mam problem, ze nektere dny mi jen samotna exekuce prikazu trva vice jak minutu. Chtel bych vedet, jestli je to omezeni paper accountu u IB nebo mam hledat problem v IB_INSYNC. Diky za pripadne info.

    • master napsal:

      Exekuce akcií je v paper trading rychlá. Naproti tomu exekuce CFD trvá neúnosně dlouho. Pokud máš na mysli CFD, tak pak je to normální stav pro paper :)

      • Balu napsal:

        Aha, diky. Zapomnel jsem napsat, ze testuji prave na CFD. Po zalozeni ostreho uctu mohu ocekavat rychlejsi exekuci? Test tedy prepnu na akcie :)

  7. master napsal:

    Jop. V realu je exekuce CFD rychla :)

  8. nemozny napsal:

    matplotlib.pyplot
    https://i.imgur.com/UJPyiLa.png
    (a ne, není to 90tka..)

  9. nemozny napsal:

    (tento blog asi nemá rád odkazy, tak je zkusím odmazávat, abych prošel)
    Tohle jsem hledal – pyfolio is a Python library for performance and risk analysis of financial portfolios developed by Quantopian Inc. It works well with the Zipline open source backtesting library.
    https://github.com/quantopian/pyfolio

    Zdá se, že pyfolio očekává vstupy
    returns : pd.Series
    Daily returns of strategy.
    positions : pd.DataFrame
    Daily net position values.
    transactions : pd.DataFrame
    Prices and amounts of executed trades. One row per trade.

    Ve tvaru dle popisu na řádcích 107 – 134 tady
    https://github.com/quantopian/pyfolio/blob/master/pyfolio/tears.py
    nebo je to vidět tady
    http://nbviewer.jupyter.org/format/slides/github/quantopian/pyfolio/blob/master/pyfolio/examples/pyfolio_talk_slides.ipynb#/13

    K tomu ta Bayesian performance analysis je celkem nářez, dokáže to na základě omezeného vzorku dat (backtestu) vykreslit t-distribuci očekávaného výkonu strategie.
    https://github.com/quantopian/pyfolio/blob/master/pyfolio/examples/bayesian.ipynb
    Co mi mé 2 semestry matematiky dovolí, se domnívám, že ta PyMC3 knihovna vytrénuje ML probabilistic model a predikuje budoucí performance.

    K tomu teda ten Zipline, kdyby chtěl někdo vyzkoušet – Zipline is an open-source algorithmic trading simulator written in Python.
    http://www.zipline.io/beginner-tutorial.html

    A pěkná prezentace, jak oba skloubit dohromady
    nbviewer.jupyter.org/format/slides/github/quantopian/pyfolio/blob/master/pyfolio/examples/pyfolio_talk_slides.ipynb#/11

  10. nemozny napsal:

    Další zajímavý projekt – https://github.com/mhallsmoore/qstrader
    Aktuálně v alpha, ale v roadmapě je napojení na IB.

  11. nemozny napsal:

    A moonshot – https://github.com/quantrocket-llc/moonshot
    Umí IB dokonce i s IBcontrollerem.

    Backtestuje vektorově – Event-driven backtests process one event at a time, where an event is usually one historical bar (or in the case of live trading, one real-time quote). Vectorized backtests process all events at once, by performing simultaneous calculations on an entire vector or matrix of data. (In pandas, a Series is a vector and a DataFrame is a matrix).

    Včetně cloudové služby, aktuálně v betě bez live tradingu
    https://www.quantrocket.com/

  12. nemozny napsal:

    Podobný jazyk jako Snail… ee vlastně Python je i R a nová Julia.

    Trading SW pak
    R – Quantstrat – https://www.rdocumentation.org/packages/quantstrat
    Julia – TradingLogic.jl – https://github.com/JuliaQuant

    Julia je kompilovaný jazyk, narozdíl od interpretovaného Pythonu a R.

Napsat komentář: Balu Zrušit odpověď na komentář

Vaše emailová adresa nebude zveřejněna.