18号 【有料】new_high.py
今回はnew_high.pyをアップします。
※注意事項
作者はPythonのプログラムを自学自習で書いています。他の人が書いたものはネットのサンプル程度しか見たことがないため、一般的な書き方ではないかもしれません。
とりあえず動けばよしという姿勢で作っています。システムトレードのプログラムを作る際の参考程度にお考え下さい。
new_high.pyは以下の場所に置いてください。
解説
NewHighクラスは売買ルール「新高値」に基づいてシグナルを発生させるクラスです。
仕掛け(買い)のシグナルはsignal.txtに書き込みます。手仕舞い(売り)のシグナルはprofit_taking.txtに書き込みます。
例)2024年1月31日にシグナル発生処理を実行した場合
デスクトップに日付のフォルダが作成され、フォルダ内に4つのファイルが作成されます。
★フォルダ名
2024-01-31
★ファイル名
error.txt
profit_taking.txt
signal.txt
start_end_time.txt
実装方法について
バックテストで良い結果が出た売買ルールをシグナル発生で実装します。
バックテスト側のTradeクラスのis_buy_signal()の内容をシグナル発生側のbuy_signal()に実装します。バックテスト側のTradeクラスのis_sell_signal()の内容をシグナル発生側のprofit_taking()に実装します。
バックテスト側とシグナル発生側では以下の箇所が異なっています。
①株価取得
シグナル発生側では処理で使用する株価を、マーケットスピード2RSS(プログラム内のコメントでは楽天RSS)で取得した値を保持しているデータフレームから取得します。
②売買シグナル判定
シグナル発生側では売買シグナルの判定結果をファイルに書き込みます。
実装の具体例
売買ルール「新高値」の場合
①定数定義
■バックテスト側
SIGNAL_DAYS = 22 * 12
VOLUME_DAYS = 22
VOLUME_TIMES = 2
RATE_THRESHOLD = 3
EXIT_DAYS = 22 * 3
LOSS_CUT_RATE = 0.90
■シグナル発生側
SIGNAL_DAYS = 22 * 12
VOLUME_DAYS = 22
VOLUME_TIMES = 2
RATE_THRESHOLD = 3
MA_DAYS_SHORT = 5
MA_DAYS_LONG = 25
SIGNAL = 'NewHigh'
シグナル発生側では時限による手仕舞いは対応していません。ロスカットについても対応していません。なのでEXIT_DAYS、LOSS_CUT_RATEについてはシグナル発生側には不要です。
※私が対応していないだけですので必要であれば処理を追加してください。
バックテスト側のis_sell_signal()ではexit_by_max_profit_ratio_in_phases()を使用していますが、シグナル発生側では購入価格や購入してからの期間などの情報を保持するようにしていないため実装できません。exit_by_max_profit_ratio_in_phases()と同じルールで手仕舞判定を行いたい場合はExcelなどで同様の計算式を作って日々管理するしかありません。代わりと言ってはなんですが、profit_taking()には移動平均線交差(デッドクロス)の実装をしておきました。その実装でMA_DAYS_SHORTとMA_DAYS_LONGを使用します。
複数のシグナルを発生させる場合にどのシグナルか判別する必要があります。そのためSIGNALに売買ルールのクラス名を設定しています。
②買い判定
異なっている箇所だけを抜粋します。
■バックテスト側 is_buy_signal()
open_list = self.price.open_list
high_list = self.price.high_list
low_list = self.price.low_list
close_list = self.price.close_list
volume_list = self.price.volume_list
price_days = self.price.days
・・・
if today_close > ytd_close_highest:
if today_volume > ytd_volume * self.VOLUME_TIMES:
if today_volume > ytd_volume_ma * self.VOLUME_TIMES:
if is_bull:
if price_range_rate >= self.RATE_THRESHOLD:
can_buy = True
■シグナル発生側 buy_signal()
open_list = self.stock_df['Open'].values
high_list = self.stock_df['High'].values
low_list = self.stock_df['Low'].values
close_list = self.stock_df['Close'].values
volume_list = self.stock_df['Volume'].values
price_days = len(close_list)
・・・
if today_close > ytd_close_highest:
if today_volume > ytd_volume * self.VOLUME_TIMES:
if today_volume > ytd_volume_ma * self.VOLUME_TIMES:
if is_bull:
if price_range_rate >= self.RATE_THRESHOLD:
if not self.ignore_signal():
# シグナルファイルに出力
FileUtil.output(self.signal_file, 'a', ' '.join([self.code, self.get_signal()]))
# 新規無視リストに追加
ignore_line = ' '.join([str(self.today), self.code, self.get_signal()])
self.ignore_new_list.append(ignore_line)
シグナル発生側では株価を楽天RSSのデータフレームから取得します。
price_daysは8号の末尾に注釈で書いたとおり、株価リストの要素数と同じ値です。
判定結果をsignal.txtに出力し、新規無視リストに追加します。signal.txtには証券コードと定数SIGNALの値を書き込みます。新規無視リストはシグナルが発生しても指定日数の間はsignal.txtに書き込まないようにするためのものです。シグナルが連日発生してややこしいと思い追加しました。
③利食い判定
異なっている箇所だけを抜粋します。
■バックテスト側 is_sell_signal()
if self.exit_by_max_profit_ratio_in_phases(profit_rate1, profit_rate2, profit_rate3,
stop_ratio1, stop_ratio2, stop_ratio3, True):
can_sell = True
■シグナル発生側 profit_taking()
close_list = self.stock_df['Close'].values
price_days = len(close_list)
・・・
if ytd_close_ma_short > ytd_close_ma_long:
if close_ma_short <= close_ma_long:
# 利食いファイルに出力
FileUtil.output(self.profit_file, 'a', ' '.join([self.code, self.get_signal()]))
シグナル発生側でexit_by_max_profit_ratio_in_phases()を実装できないため苦肉の策で移動平均線交差(デッドクロス)の実装をしています。バックテスト側とシグナル発生側の処理で異なるのは、価格リストの取得方法、price_daysの取得方法、シグナルの判定結果の扱い方です。シグナル発生側では判定結果をprofit_taking.txtに出力します。証券コードと定数SIGNALの値を書き込みます。
※get_signal()でself.codeとself.SIGNALを連結して返せばいいのにと思いますが、そのうち人類はイルカに滅ぼされてしまうので直していません。
ここから先は
¥ 100
この記事が参加している募集
この記事が気に入ったらチップで応援してみませんか?