定量的取引システムのバックテスト--- RQalpha、qstrade研究ノート



Quantitative Trading System Backtesting Rqalpha



A、RQalpha

githubアドレス https://github.com/ricequant/rqalpha

1、test.pyファイルを実行し、「logbook.base」という名前のモジュールを表示しません。



インストールする前にアンインストールを解決します:pipアンインストールログブックpipインストールログブック

2、表示されます:RuntimeError:アカウントと初期資金を設定します。



解決する:

二、ジップライン

githubアドレス https://github.com/quantopian/zipline ジップライン学習教材 http://www.zipline.io/

ジップラインコードはもっと悪いコピーです



3、qstrade

githubアドレス https://github.com/mhallsmoore/qstrader

提案された、一時的な学習qstradeを聞いてください。より少ないコード、迅速。

テスト:

価格設定用のデータCSVが見つからなかったため、ティッカーSPYをサブスクライブできませんでした。
価格設定用のデータCSVが見つからなかったため、ティッカーAGGをサブスクライブできませんでした。
トレースバック(最後の最後の呼び出し):
ファイル 'E:/qstrader-master/examples/monthly_liquidate_rebalance_backtest.py'、行108、
run(config、testing、tickers、filename)
ファイル 'E:/qstrader-master/examples/monthly_liquidate_rebalance_backtest.py'、行94、実行中

ポリシーコードで、以下を後ろに追加します。

import os from munch import munchify os.chdir('E:\qstrader-master') config = munchify({'CSV_DATA_DIR': 'data', 'OUTPUT_DIR': 'out', 'testing': True})

画像の保存を変更する必要があります:

Trading_session.pyファイルの最後の部分である最後から2番目の行self.statistics.plot_results()--------> self.statistics.save()

tearsheet.pyファイルの最後の部分、self.plot_results()----------> self.plot_results(ファイル名)

学習問題の要約:

1、buy_and_hold_backtest.pyファイルの実行中にエラーが発生しました。

ファイル 'E: qstrader-master qstrader price_handler yahoo_daily_csv_bar.py'、68行目、_merge_sort_ticker_data
df = pd.concat(self.tickers_data.values())。sort_index()
ファイル 'D: Anaconda3 lib site-packages pandas core reshape concat.py'、行206、concat
copy = copy)
ファイル 'D: Anaconda3 lib site-packages pandas core reshape concat.py'、239行目、__ init__
ValueError( '連結するオブジェクトがありません')を発生させます
ValueError:連結するオブジェクトがありません

1、self.tickers_dataは何ですか? -> self.csv_dir = csv_dir、csv_dirはどこにありますか? ->

2、位置エラー:backtest = TradingSession(config、strategy、tickers、initial_equity、start_date、end_date、events_queue、title = title)がインスタンス化され、

パラメータは次のとおりです。

config-> TEST == munchify({'CSV_DATA_DIR': 'data'、 'OUTPUT_DIR': 'out'})

ストラテジー->インスタンス化、BuyAndHoldStrategy(ティッカー[0]、events_queue)

ティッカー-> ['SPY']

initial_equity-> 10000

start_date-> datetime.datetime(2000,1,1)

end_date-> datetime.datetime(2014,1,1)

events_queue-> queue.Queue()

タイトル-> ['SPYでのバイアンドホールドの例']

よく見ると、qstrader Trading_session.pyの間違った場所、トレーディング。なぜ/どのようにこの段階に入るのですか?

それでもコードを注意深く見る必要があります。メソッドを開始するには、次の__init __()にself._config_sessionがあります。クラスの初期化中に、関数をバックテストする必要があります。

-> def _config_session(self):-> self.price_handler = YahooDailyCsvBarPriceHandler(self.config.CSV_DATA_DIR、self.events_queue、self.tickers、

start_date = self.start_date、end_date = self.end_date)

'' '要求された各金融商品のcsvファイルを読み取り、開く-高-低-収入-取引量(OHLCV)を読み取り、それらをBarEventsとして提供されたイベントキューにストリーミングするように設計されています' ''

-> self.subscribe_ticker(ティッカー)ティッカーをサブスクライブします->以前にサブスクライブしたself._open_ticker_price_csv(ティッカー)

-> self._merge_sort_ticker_data()マージティッカー

デバッグ後、SPY.csvファイルの読み取り部分にエラーコードが見つかりました。コードは次のように表示されます。

ticker_path = os.path.join(self.csv_dir、 '%s.csv'%ticker)

self.tickers_data [ticker] = pd.io.parser.read_csv(ticker_path、....)、奇妙な、ここで次のステップをデバッグします。ticker_pathはなくなりました。

さらに、問題は以下の例のパス、buy_and_hold_backtest.pyパスであることがわかりました。

import os os.getcwd() Out[7]: 'E:\qstrader-master\examples'

また、ファイルパスは次のとおりです。'E: qstrader-master data '、ticker_path =' data \ SPY.csv '。

そのドキュメントの読み取り位置は次のとおりです。'E: qstrader-master examples data SPY.csv '、すべてのファイルを読み取ることはできません。次のように変更できます。

まず、ファイルを追加できますbuy_and_hold_backtest.py:import os os.chdir( 'E:\ qstrader-master')

次に、buy_and_hold_backtest.pyファイルでPythonコンソールを実行し、examples buy_and_hold_backtest.pyを実行します。

run examplesuy_and_hold_backtest.py Backend Qt5Agg is interactive backend. Turning interactive mode on. ticker: SPY self.tickers: {} ticker_path: dataSPY.csv Running Backtest... --------------------------------- Backtest complete. Sharpe Ratio: 0.25 Max Drawdown: 79.59%

2、デバッグプロセスの背後、循環プロセス:

Trading_session.py 1つのクラスのみ:TradingSession(オブジェクト)

注:__ init__の場合、self._config_session()を実行します。

4つのメソッドがあります:1、_config_session(self):2、_continue_loop_condition(self)3、_run_session(self)4、start_trading(self、testing = False)

Buy_and_hold_backtest.pyで、TradingSessionが最初にインスタンス化され、次にstart_tradingメソッドを実行すると、次のプロセスが実行されます。

self._config_session()---->

self.start_trading()-----> self._run_session()----> self._continue_loop_condition

3、_run_session(self)の操作方法

一方self._continue_loop_condition():

試してください:

event = self.events_queue.get(False)

queue.Emptyを除く:

self.price_handler.stream_next()

そうしないと:

イベントがNoneでない場合:

if(event.type == EventType.TICKまたはevent.type == EventType.BAR):。。。。。

#dir(イベント)-> 6つのプロパティがありますアクションprint_order数量ティッカータイプtypename ---> event.type = EventType.ORDER、elifを入力するための条件を満たしていません

エリフevent.type == EventType.ORDER:

self.execution_handler.execute_order(event)

---->

def _continue_loop_condition(self):

self.session_type == 'backtest'の場合:

self.price_handler.continue_backtestを返します

そうしないと:

datetime.now()を返します

表示:self.price_handler from:qstrader.price_handler.yahoo_daily_csv_bar.YahooDailyCsvBarPriceHandlerオブジェクト

debug self.price_handler.continue_backtestがTrueの場合、続行します。

->

self.execution_handler.execute_order(event)差出人:qstrader / execute_handler / ib_simulated.py

def execute_order(self、event):

event.type == EventType.ORDERの場合:

#OrderEventから値を取得する

タイムスタンプ=self.price_handler.get_last_timestamp(event.ticker)

ティッカー= event.ticker

action = event.action

数量= event.quantity

#約定価格を取得

もしself.price_handler.istick():

bid、ask = self.price_handler.get_best_bid_ask(ticker)

fill_price = event.action == 'BOT'の最初の入札かどうかを尋ねる

そうしないと:

close_price =self.price_handler.get_last_close(ticker)

fill_price = close_price

#ダミー取引所を設定し、取引手数料ダミーを計算します:シミュレートされた取引

交換= 'ARCA'

手数料=self.calculate_ib_commission(quantity、fill_price)

#FillEventを作成し、イベントキューに配置します

fill_event =FillEvent(タイムスタンプ、ティッカー、アクション、数量、交換、fill_price、手数料)#インスタンス化されたクラスFillEvent

self.events_queue.put(fill_event)

self.complianceがNoneでない場合:

self.compliance.record_trade(fill_event)

---->

self.price_handlerFrom:qstrader / price_handler / base.py、3つのクラスで構成されています:

1、AbstractPriceHandler(オブジェクト)タイプ2、AbstractTickPriceHandler(AbstractPriceHandler)クラス3、AbstractBarPriceHandler(AbstractPriceHandler)クラス

self.price_handler.get_last_timestamp()AbstractPriceHandler(オブジェクト)クラスメソッドであり、

def get_last_timestamp(self、ticker):

self.tickersのティッカーの場合:

timestamp = self.tickers [ticker] ['timestamp']

タイムスタンプを返す

self.price_handler.istick()クラス:AbstractBarPriceHandler(AbstractPriceHandler)メソッド:istick

def istick(self):

Falseを返す

def isbar(self):

Trueを返す

self.price_handler.get_last_close(self、ticker)クラスのAbstractBarPriceHandler(AbstractPriceHandler)メソッドです

def get_last_clost(self、ticker):#ticker: ‘SPY’

self.tickersのティッカーの場合:#self.tickersは:{'SPY':{'close':1454375000、 'adj_close':1058253320、 'timestamp':Timestamp( '2000-01-03 00:00:00') }}

close_price = self.tickers [ticker] ['close']#self.tickers [ticker] is 辞書

close_priceを返します #ib_similated.pyでclose_priceを取得します

----->

ティッカー=イベント。ティッカーアクション=イベント。アクションイベントから:qstrader.event.OrderEvent位置qstrader / event.py

event.pyは次のとおりです。合計7つのカテゴリ、基本クラスのイベント。

列挙型インポート列挙型から

EventType = Enum( 'EventType'、 'TICK BAR SIGNAL ORDER FILL SENTIMENT')

1、Event(object):2、TickEvent(Event)3、BarEvent(Event)4、SignalEvent(Event)5、OrderEvent(Event)6、FillEvent(Event)7、SentimentEvent(Event)

fill_event = FillEvent(タイムスタンプ、ティッカー、アクション、数量、交換、fill_price、手数料)

ドライライブが多く、クラスに入るだけで、プロパティ値が

---->

self.calculate_ib_commission(quantity、fill_price)差出人:execution_handler / ib_simulated.py

以下を含むクラス:IBSimulatedExecutionHandler(AbstractExecutionHandler)

def __init __(self、events_queue、price_handler、compliance = None):

defcalculate_ib_commission(self、quantity、fill_price):

コミッション=最小(0.5 * fill_price *数量、最大(1.0,0.005 *数量))

PriceParser.parse(commission)を返します

----->

self.compliance.record_trade(fill_event)差出人:qstrader / Compliance / example.pyファイル、1つのクラスのみ

from .base import AbstractCompliance from:qstrader / Compliance /base.pyにコンテンツがありません

クラス:ExampleCompliance(AbstractCompliance)#

トランザクションレコードを保存する

3、プロセスを実行しているビューをデバッグします

まず、以前にトランザクションに投資したリストを作成します。

run(config、testing、tickers、filename)---->

title / initial_equity / start_date / end_date / events_queue /戦略、ロードストラテジー(MonthlyLiquidateRebalanceStrategy(tickers、events_queue)----->

tickers_invested:{'SPY':False、 'AGG':False}、初期化投資ティッカー、----->

ticker_weights / position_sizer、ロードされたクラスの数position(LiquidateRebalancePositionSizer(ticker_weights))------->

qstrader / position_sizer / rebalance.py ----- position_sizer -----取得したinitial_order ----------->

バックテストを確立するbacktest = TradingSession(config、strategy、tickers、initial_equity、start_date、end_date、events_queue、position_sizer = position_sizer、title、

ベンチマーク=ティッカー[0])--------->

バックテストの結果を開始= backtest.start_trading(テスト=テスト)------------->

以前の作業を終了しましたが、現在は測定されており、バックテストがインスタンス化され、メソッドstart_trading呼び出しがインスタンス化されています。 ------->

self._config_session()、クラスは初期化中に測定する必要がありますPress、self.price_handler = YahooDailyCsvBarPriceHandler(self.config.CSV_DATA_DIR、self.events_queue、

self.tickers、start_date = self.start_date、end_date = self.end_date)----->

event = self.events_queue.get(False)がイベントキューで取得され、各バーイベント--------->

self.strategy.calculate_signals(イベント)、ロード戦略、シグナルの計算----->

self.portfolio_handler.update_portfolio_value()、ポートフォリオ値を更新します、------>

self.statistics.update(event.time、self.portfolio_handler)、更新された統計------->

戻り結果戻り結果

4、考えて、場所の複雑さを理解していない

A、event.py、EventType、EventType = Enum( 'EventTye'、 'TICK BAR SIGNAL FILL')

TICKBARそれぞれTICKBARイベントデータ、SIGNAL FILLどのような役割ですか?各イベントを処理するのは実行中のようなものですか?

Buy_and_hold_backtest.pyデバッグビューの場合、イベントのフローは次のとおりです。

---->

Buy_and_hold_backtest.py関数:calculate_signals(self、event)

signal = SignalEvent(self.ticker、 'BOT'、suggested_quantity = self.base_quantity)

self.events_queue.put(signal)-----------------------> Trading_session.py self.portfolio_handler.on_signal(event)

Portfolio_handler.py関数:on_signal(self、signal_event)

#単一のシグナルイベントから注文の初期リストを作成します

initial_order = self._create_order_from_signal(signal_event)

#最初の注文からの取引数を設定します

sized_order = self.position_sizer.size_order(self.portfolio、initial_order)

#風角制御全体を再編集するか、注文を削除します

order_events = self.risk_manager.refine_orders(self.portfolio、sized_order)

#イベントキューに入れられた注文

self._place_orders_onto_queue(order_events)

次に、システムをテストするために単純なバージョンをコピーして戻す方法は?

不要な部分を取り除くためには、各部分の全体的な操作プロセスと機能を理解する必要があります。

1、完全なrisk_managerを削除します

2、ORDERイベント、SIGNALイベントをイベントから直接FILLに削除します

ORDERイベントは何もしませんでした、1、order_event ----> fill_event 2、self.compliance.record_trade(fill_event)

3、変更されたself.position_sizer Trading_session.pyファイル(1)、self.position_sizerのtrading_session.pyはやや反復的(2)、直接生成パラメーターが順序、ティック、アクション、数量を必要とするときにシグナルを生成します。

今、問題は何ですか? SIGNALの問題が発生し、1、トランザクションへのシグナルで、トランザクションはすぐにパラメータを生成する必要があります(コードがポリシーテンプレートを記述できるよりも大きい)

したがって、portfolio_handler.pyに問題があり、order_events self.position_sizerを生成するときに少しロードすると、削除されました。次のように言います:

order_events = self.position_sizer.size_order(self.portfolio、initial_order)

on_signalportfolio_handler.pyを必要なパラメータに変更できます。

ここでの問題は、主な戦略の数量の数がゼロであり、負荷position_sizerが数量を変更しないことです。

4、各ファイル関数の最初の分析portfolio.py、postition.py、tearsheet.pyファイル。

Portfolio.pyから2つの引数、price_handlerとcash price_handlerは、portfolio_handler.py、trading_session.pyパラメーター、trading_session.pyのパラメーターです。

self.price_handler = YahooDailyCsvBarPriceHandler(self.config.CSV_DATA_DIR、self.events_quue、self.tickers、start_date = self.start_date、end_date = self.end_date)

転送プロセスパラメータ:buy_and_hold_backtest.py initial_equity ----> Trading_session self.equity = PriceParser.parse(equity)----> Portfolio_handler.py self.initial_cash = initial_cash ----> Portfolio.py self.init_cash = cash

Portfolio.pyパラメーター:

self.price_handler = price_handler self.init_cash = cash self.equity = cash self.cur_cash = cash self.position = {} self.closed_positions = [] self.realised_pnl = 0

5、部分から1000万を掛けた修正、それはとても奇妙に見えました。

第三に、問題は次のとおりです。別のクラスのオブジェクトのインスタンスとして定義されたTradingSessionクラス属性(self.price_handler self.suggested_order self.position_size self.portfolio_handler self.compliance self.statistics)、例のプロセスのプロパティ、パラメータの入力方法は?なぜ私は書くのですか、他に書かれていませんか?

回答:クラスデータ構造の性質、オブジェクトは引数のインスタンス化であり、それは可能です。その主な役割は次のとおりです。関数とパラメーターは、親オブジェクト内の子オブジェクトを指示します。

オブジェクトインスタンス化パラメータの子を使用して、親グローバル変数パラメータを直接渡すことができます。子オブジェクトインスタンス化パラメータは、次に示すように、インスタンスの別のサブ属性に渡すことができます。self.portfolio_handlerクラスインスタンスPortfolioHandlerオブジェクト(プロパティの1つとして) Trading_session、self.portfolio_handlerTearsheetStatisticsインスタンス化パラメータとプロセスの。

第四に、変更

1、position.pytransact_sharesを書き換える関数

2、(x、2)の周りのprice_parser.py行44の小数点以下2桁で、分割可能を変更することに加えて位置

手数料はib_simulated.py0に設定され、印刷量が非常に多く、中間のバグが見つかりました

解決策:以下に示すように、vnpyデータ調整関数を使用してprice_parser.pyファイルのコピーを作成し、変更を加えます。a、コンプライアンスファイル、record_tradeの表示方法、4つのパラメーターは省略できます。

3、