IB証券でシストレ|CFDのダウ30と日経225をMACDでデイトレード

スポンサーリンク

IB証券(インタラクティブ・ブローカーズ証券)にてCFDのダウ30と日経225をMACDでデイトレードするシストレを紹介します。Pythonで構築したシステムは、コピペだけでほとんどそのままシストレを開始できます。状況次第ですが年利10%は固いです。

重要
本ページのシストレについて、IB証券でこのCFDは取引できないことが判明しました。
先物であれば取引ができますので、先物で再検討します。少々お待ち下さい。
スポンサーリンク

前提

投資の考え方

今回の投資手法の指針は、以下のように考えました。

「勝つためには負けないこと」

馬鹿じゃねえか。当たり前だろう。という皆様、私もそう思いました。
しかし、ある時、あるハイレバでガンガン儲けているYouTubeの動画で言っていた以下のことを思い出しました。

「FXのUSD/JPYは、極端な価格のポジションでは無く、且つレバレッジが大きく無ければいつか勝てる」

そうだ!これだ!

ということは、トレンドが並行か、右肩上がりの買い、もしくは右肩下がりの売りを仕掛ければ、いつかは利食いできる。

でも、これに近いことというか、これをやっていたのですが、それでも負けました。というか大負けです。

VIXという恐怖指数の投資ですが、いつかは世の中は安定するから下がるという投資です。
上記の条件に当てはめると、13ドルくらいの売り(極端というほどでもないかと。。)、レバレッジというより70ドルに暴騰してもいいようにたっぷりの証拠金を積んでいました。が、なんと歴代1位になる高騰を見せ、あっさりと玉砕しました。。。

これらを踏まえ、今回の投資の方向性の考え方です。

  1. DOW30、日経225を買いで仕掛ける。
    • 現在の価格は最高値の8割くらい。あがる余地は十分ある。
    • 下がるリスクも最大2割と考える。(3月に最高値の6割くらいになったから。
  2. 買いのみ。売りはやらない。
    • 今よりは世の中良くなると考えるから。
  3. インジゲーターMacdの1分足と5分足が買いクロスになったら買い。
    • 根拠は弱いのですが、私が手動でトレードしているときに、概ねその動きに合わせると利益が出そうな気がしたからです。
  4. 上昇トレンドの時だけトレードする。
    • 下げ相場で逆張りはうまくいかないです。
    • 上げ相場の下げを狙うスタンスです。

目標

同期間のそれぞれの株価上昇率より10%以上、上回るパフォーマンスを出せること。
(特に意味はないのですが、同じパフォーマンスだったらシストレでなく普通に買えばいいだけになります。ではどれくらい以上のパフォーマンスがいいのかというと、これは個人の感覚かと思います。ということで10%くらいはなんとかしたいと。

シストレの投資手法

金融商品CFD(ダウ30、日経225)
金融機関IB証券(インタラクティブ・ブローカーズ証券)
資金DOW30:5万米ドル、日経225:500万円(これらはバックテスト用という意味です。
売買買いのみ
売買数量DOW30:5枚、日経225:500枚の固定(複利効果を使わず
投資判断買い発注インジゲーターMacdの1分足と5分足、日足が買いクロス(バックテストの結果、日足を含めない方がパフォーマンスが良かった。
利確インジゲーターMacdの1分足か5分足のどちらかが買いクロスを外れた場合、且つ利益が100pips以上
損切しない
売り発注
利確
損切
スクロールできます

投資対象の商品情報

IB証券のCDFはイギリスのIB証券の商品となっており、欧州証券市場監督局(ESMA)によるルールが適用されるようです。

ダウ30日経225
シンボルIBUS30IBJP225
通貨USDJPY
取引数量(枚1〜201〜850
手数料*片道
(最低手数料)
0.01%
($1.00)
0.01%
(¥40)
取引時間
(BST、英国時間
通常取引時間 08:00~21:00
取引可能時間 03:00~16:00
通常取引時間 01:00~07:10
取引可能時間 20:00~02:10
スクロールできます

*手数料は約定レートに対してのパーセントです。片道となっています。決済時の約定レートで手数料が発生します。

オーバーナイトの借入金利はベンチマークの± 1.5%となっています。

とあるので注意しましょう。現時点では買いの場合は金利をもらえます。

ホーム | インタラクティブ・ブローカーズ証券株式会社
株式やオプション、先物、通貨、そして債券やファンドに直接アクセス可能な、トレーダー、投資家、およびアドバイザーのお客様のためのオンライン取引ソリューションです。透明性の高い低額な約定手数料と借入金利、そして最良約定のためのサポートです。

その他、詳しくは以下を参照してください。

IB Index CFDs - Facts and Q&A | Knowledge Base

証拠金は以下を参照してください。

ホーム | インタラクティブ・ブローカーズ証券株式会社
株式やオプション、先物、通貨、そして債券やファンドに直接アクセス可能な、トレーダー、投資家、およびアドバイザーのお客様のためのオンライン取引ソリューションです。透明性の高い低額な約定手数料と借入金利、そして最良約定のためのサポートです。
Overview of ESMA CFD Rules Implementation at IBKR (UK) - Retail Investors Only

システム要件

開発環境

  • OS:macOS Carolina 10.15.4
  • 言語:Python 3.7.2
  • 開発ツール
    • バックテスト用システム:Jupyter Notebook 1.0.0
    • 本番用システム:Visual Studio Code 1.45.1

本番環境

  • OS:Windows Server 2012 R2(AWS
  • 言語:Python 3.7.4

あれ。Pythonのバージョンがあっていませんね。。。気にしない気にしない。。。

バックテスト

システム

以下はGithubにアップしていますので、ダウンロードして利用してください。
(左下のファイル名をクリックするとGithubのサイトに遷移します。「Download ZIP」をクリックするとダウンロードできます。)

過去データはIB証券からダウンロードしたものを利用しているのですが、それは再配布禁止とIB証券の規約になっていたと思いますので、手間ですが、ご自身でダウンロードしてください。

過去データは、1分足、5分足、日足を使っています。

ファイル名は投資対象のシンボル名+足(1分足:M1、5分足:M5、日足:D1)になっています。
例)IBJP225_D1.csv

ソースにゴミがあったりしますが、すいません。

注意

  • バックテストに手数料は含まれていません。
  • スプレッドは固定でテストしていますが、実際には変動します。

Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
view raw 1-test.ipynb hosted with ❤ by GitHub

結果

当初の投資手法の通り

シンボル投資回数期間日数回数/日数損益PIPS期間PIPS損益/期間PIPS資金残上昇率利益回数損失回数勝率
IBUS3072231.80%1120.85627178.80%55,604111.20%70100%
IBJP225131872.20%1085.03111297.60%5,542,515110.90%120100%
スクロールできます

投資判断から日足のmacdの判断を除く

シンボル投資回数期間日数回数/日数損益PIPS期間PIPS損益/期間PIPS資金残上昇率利益回数損失回数勝率
IBUS30122254.50%1637.27627261.10%58,186116.40%110100%
IBJP2252018111.10%1476.421112132.80%5,738,210114.80%190100%
スクロールできます

日足のmacdの判断を除いたものに、投資判断に1分足のmacdが0以上の場合に実行するを追加

シンボル投資回数期間日数回数/日数損益PIPS期間PIPS損益/期間PIPS資金残上昇率利益回数損失回数勝率
IBUS30122254.50%1586.05627253.00%57,930115.90%110100%
IBJP2252018111.10%1457.41112131.10%5,728,700114.60%190100%
スクロールできます

まとめ

  • 投資方針に下降トレンド時に対策として日足のmacdの判断を付けたがパフォーマンスが落ちた。
    (上記の投資手法など訂正済み。ソースには残骸があります。

以下は、投資判断から日足のmacdの判断を除いた場合です。

  • 約1ヶ月間のテストとなったがパフォーマンスは月利15%ほどだった。
  • 期間の株価(CFD)の上昇率より、ダウ30は約2.6倍、日経は約1.3倍となった。
  • 日経225よりダウ30の方がパフォーマンスが良かった。多分、ボラティリティが大きいということだと思います。
  • 作りながら1分足のMACDが1以上という追加の条件を考えたが、パフォーマンスは少し落ちた。
    (上記のソースに残骸があります。

課題

  1. 長期間などのテストを再実施する。
  2. 上記ともつながるが、今回のようなショックで天井で掴むリスクがある。この回避方法はないか。
  3. 期間中の最大の含み損はいくらになるのか。またロスカットされないのか。

今後の方針

基本的に良い結果を得られたので、課題事項を確認した上で、本番に入りたいと思います。

課題の対応

以下の2つをバックテストしました。

  • 長期間などのテストを再実施する。
  • 期間中の最大の含み損はいくらになるのか。またロスカットされないのか。

2020年の年初から

シンボル投資回数期間日数回数/日数損益PIPS期間PIPS損益/期間PIPS資金残上昇率利益回数損失回数勝率含み損PIPS左記の価格
IBUS301210111.90%1262.84-4008-31.50%56,314112.60%110100%-1120829460
IBJP2253783.80%139.02-3680-3.80%5,069,510101.40%20100%-784924090
スクロールできます
まとめ
  • 今回のコロナショックがあったので想定通りだったが、天井を掴んでそのままトレードがストップ
  • それでも途中までは、DOW30は112.6%の利益を出しています。
最大含み損の時のロスカットの検証
IBUS30IBJP225
建玉時貸付資産を含む資産価値現金00
貸付-97,300-7,045,000
金融資産147,30012,045,000
ELV50,0005,000,000
維持証拠金金融資産147,30012,045,000
維持証拠金率25%25%
MM36,8253,011,250
証拠金余力ELV – MM13,1751,988,750
最大含み損の時貸付資産を含む資産価値現金00
貸付-97,300-7,045,000
金融資産91,2608,120,500
ELV-6,0401,075,500
維持証拠金金融資産91,2608,120,500
維持証拠金率25%25%
MM22,8152,030,125
証拠金余力ELV – MM-28,855-954,625
スクロールできます

ぶっちぎりのロスカットですね。資金を増やすか、数量を減らさないとダメですね

2019年のデータ

シンボル投資回数期間日数回数/日数損益PIPS期間PIPS損益/期間PIPS資金残上昇率利益回数損失回数勝率含み損左記の価格
IBUS305125220.20%5793.65451106.30%78,968157.90%500100%-2073.0127314.01
IBJP2254224117.40%4744.144230112.20%7,372,070147.40%410100%-2226.3422289.8
スクロールできます
まとめ
  • 2019年は上昇トレンドでしたが、株価の上昇よりも本シストレの方が少しに高かったです。10%前後ですね。まぁ目標は達成していると判断しましょう。
  • 年利はきたーって感じです。約1.5倍に資産が増えています。
    • ダウ30:年利157.9%
    • 日経225:年利147.4%
  • 回数/日数が20%弱くらいなので週に1回くらいの投資になります
最大含み損の時のロスカットの検証
IBUS30IBJP225
建玉時貸付資産を含む資産価値現金00
貸付-86,570-6,144,500
金融資産136,57011,144,500
ELV50,0005,000,000
維持証拠金金融資産136,57011,144,500
維持証拠金率25%25%
MM34,1422,786,125
証拠金余力ELV – MM15,8582,213,875
最大含み損の時貸付資産を含む資産価値現金00
貸付-86,570-6,144,500
金融資産126,20510,031,500
ELV39,6353,887,000
維持証拠金金融資産126,20510,031,500
維持証拠金率25%25%
MM31,5512,507,875
証拠金余力ELV – MM8,0841,379,125
スクロールできます

ロスカットされなかったようです。

しかし、もう少し資金を増やすか、数量を減らさないと危険ですね

2018年のデータ

シンボル投資回数期間日数回数/日数損益PIPS期間PIPS損益/期間PIPS資金残上昇率利益回数損失回数勝率含み損左記の価格
IBUS30162516.40%1894.41-1620-116.90%59,472118.90%150100%-524526935
IBJP225102454.10%831.86-3270-25.40%5,415,930108.30%90100%-547724427
スクロールできます
まとめ
  • 株価は、年初からは少し下げていますが、ほぼ横ばいのトレンドだったようです。
  • そんな中のシストレですが、どうやら天井を掴んだようで、投資回数が著しく少ないです
  • それまでの利益は良かったようです。
    • DOW30:年利18.9%
    • 日経225:年利8.3%
最大含み損の時のロスカットの検証
IBUS30IBJP225
建玉時貸付資産を含む資産価値現金00
貸付-84,675-7,213,500
金融資産134,67512,213,500
ELV50,0005,000,000
維持証拠金金融資産134,67512,213,500
維持証拠金率25%25%
MM33,6693,053,375
証拠金余力ELV – MM16,3311,946,625
最大含み損の時貸付資産を含む資産価値現金00
貸付-84,675-7,213,500
金融資産108,4509,475,000
ELV23,7752,261,500
維持証拠金金融資産108,4509,475,000
維持証拠金率25%25%
MM27,1122,368,750
証拠金余力ELV – MM-3,338-107,250
スクロールできます

ほんの少しですが、資金を増やすか、数量を減らさないとロスカットされます

もしかするとそれまでの利益でギリギリですが、ロスカットされなかったかも知れません。
日経でいうと、上記では10万円強足りずにロスカットですが、それまでに40万円ほどの利益を出していますので、助かっていたようです。DOW30は同じですね。

しかし、タイミングの問題で、この頂点の時にこのシストレを初めていたら利益はないのでロスカットされます。アウトです。

課題のまとめ

  • 資金の余裕がなかったり、ロスカットされてしまいます。
    2020年の初期からのデータで、以下の設定で、軽くバックテストしました。
    • DOW30:数量を3枚
      29,460米ドル × 3枚 = 88,380米ドル – 現金50,000米ドル = 38,380米ドル × 1.33 = 51,045米ドル
      29,460米ドル -11,208pips = 18,252米ドル × 3枚 = 54,756米ドル
    • 日経225:数量を300枚
      24,090円 × 300枚 = 7,227,000円 – 現金5,000,000円 = 2,227,000円 × 1.33 = 2,961,910円
      24,090円 -7,849pips = 16,241円 × 300枚 = 4,872,300円

上記のように減らせば、今回のショックでも耐えうることがわかりました。

  • 天井掴みは仕方ないですね。ただ、基本的には右肩上がりだと信じるしかないかも知れません。
    あとはいつ始めるかのタイミング次第ですね。

本番

作成しました。こんな感じかなと思います。

本来であれば、バックテストと本番のシステムは同じものがいいと思うのですが、いろいろ面倒なので別に作りました。

その他、所々、ちょっとと思うところはありますが。。。

インポートしている独自のライブラリが2つあります。

  • import cls_db
  • import cls_lineself.access_tokenのところは設定してください。
これもGitHub Gistアップしています。余計な関数が多いですが。

シストレの本体

  • CFDsのところで、購入する数量を変更してください。現状はバックテストに合わせています。
  • # Systemのコメント以下のところのIPやポート、クライアントIDは自身の仕様に変更してください。
  • # 通知のコメント以下のところは不要でしたら削除してください。
  • 通常取引時間のみ取引しています。時間外取引は停止します。

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
@author: novonovo
"""
# --------------------------------------------------------------------------
# ライブラリの読み込み
import os
import sys
import traceback
import pandas as pd
from datetime import datetime, date, timedelta
from time import sleep
from pytz import timezone
import sqlite3
from queue import Queue
import threading
from ib_insync import *
import cls_db
import cls_line
# インジゲーター
from pyti.moving_average_convergence_divergence import moving_average_convergence_divergence as macd
from pyti.simple_moving_average import simple_moving_average as sma
# --------------------------------------------------------------------------
# タイムゾーン 英国時間 Europe/London
# 日経 通常取引時間 01:00~07:10*** BST 取引可能時間 20:00~02:10 BST(英国時間
# ダウ 通常取引時間 08:00~21:00*** BST 取引可能時間 03:00~16:00 BST(英国時間
data_timezone = 'America/New_York'
trade_timezone = 'Europe/London'
# --------------------------------------------------------------------------
# 設定
# Trading
CFDs = {
'IBJP225' : {
'EXCHANGE' : 'SMART',
'CURRENCY' : 'JPY',
'UNITS' : 500
},
'IBUS30' : {
'EXCHANGE' : 'SMART',
'CURRENCY' : 'USD',
'UNITS' : 5
}
}
PROFIT_PIPS = 100 # 利確PIPS
# Indicator
MACD_SLOW = 26
MACD_FAST = 12
SMA_PERIOD = 9
# System
tws_localIP = '127.0.0.1'
tws_port = 4002
tws_clientId = 90001
dbpath = 'trade.sqlite'
error_count = 0
shut_down_flag = False
LONG = 'BUY'
SHORT = 'SELL'
fmt = "%Y-%m-%d %H:%M:00%z"
# --------------------------------------------------------------------------
# インスタンス設定
db_ins = cls_db.db(dbpath)
line_ins = cls_line.line()
# # --------------------------------------------------------------------------
# キューの設定
line_message = Queue()
# --------------------------------------------------------------------------
# DBの確認
if os.path.isfile(dbpath) == False:
db_ins.create_db()
# --------------------------------------------------------------------------
class trading:
# Default settings
def __init__(self):
self.ib = IB()
self.ib.errorEvent += self.ib_onErrorEvent
self.flag_notice = False
def ib_connect(self):
self.ib.connect(tws_localIP, tws_port, clientId=tws_clientId)
def ib_onErrorEvent(self, reqId, error_code, error_string, contract):
print('error_code!!',error_code, error_string)
if error_code == 1100:
self.ib.sleep(10)
elif error_code == 201: # Canceled order
self.ib.sleep(60)
def get_bars_df(self, Symbol, BarSizes):
# 日足を取得
contract = CFD(Symbol, CFDs[Symbol]['EXCHANGE']) # 銘柄 取引所
bars = self.ib.reqHistoricalData(
contract,
endDateTime = '',
durationStr = '2 D',
barSizeSetting = BarSizes,
whatToShow = 'MIDPOINT',
useRTH = True,
formatDate = 1
)
df = util.df(bars)
return df
def get_tick(self, Symbol):
contracts = CFD(Symbol, exchange=CFDs[Symbol]['EXCHANGE'])
self.ib.qualifyContracts(contracts)
self.ib.reqMktData(contracts, '', False, False)
ticker = self.ib.ticker(contracts)
self.ib.sleep(1)
return ticker.bid
def get_jpy_rates(self, final_pl):
contract = Forex('USDJPY', exchange='IDEALPRO')
bars = self.ib.reqHistoricalData(
contract,
endDateTime='',
durationStr='1 D',
barSizeSetting='1 day',
whatToShow='MIDPOINT',
useRTH=True,
formatDate=1)
jpy_rates = bars[0].close * final_pl
return jpy_rates
def get_positions(self, trade_symbol):
positions = {}
for details in self.ib.positions():
if details.contract.symbol == trade_symbol:
positions['units'] = int(details.position)
positions['rates'] = details.avgCost
return positions
def get_portfolio(self):
# Get portfolio from IB
self.ib.sleep(0.5)
for details in self.ib.accountSummary():
if details.account in ['DU1580586','U3203720'] and details.tag == 'TotalCashValue':
portfolio = int(float(details.value))
if details.account in ['DU1580586','U3203720'] and details.tag == 'MaintMarginReq':
used_portfolio = int(float(details.value))
return portfolio, used_portfolio
def get_log(self, log, units):
# Create a tikets from the trade logs.
final_units = 0
final_rates = 0
final_pl = 0
log_status = ''
print('Get log start')
while True:
if hasattr(log, 'fills') == True:
# print(log)
if type(log.fills) is list:
if len(log.fills) != 0:
for details in log.fills:
final_units += details.execution.shares
final_pl += details.commissionReport.realizedPNL
if log.orderStatus.status == 'Filled':
final_rates = details.execution.avgPrice
log_status = 'Filled'
break
elif log.orderStatus.status == 'Cancelled':
log_status = 'Cancelled'
break
self.ib.sleep(1)
return log_status, final_units, final_rates, final_pl
def indicator(self, close_list):
macd_list = macd(close_list, MACD_FAST, MACD_SLOW)
signal_list = sma(macd_list, SMA_PERIOD)
return macd_list[-1], signal_list[-1]
# --------------------------------------------------------------------------
# トレード
def main(self, trade_symbol, data_time):
# --------------------------------------------------------------------------
# 初期値
positions = {}
trade_new = ''
trade_close = ''
UNITS = CFDs[trade_symbol]['UNITS']
# --------------------------------------------------------------------------
# 1分足を取得
while True:
df_M1 = self.get_bars_df(trade_symbol, '1 min')
last_time_M1 = df_M1.iloc[-1]['date'].strftime('%H:%M')
# print(df_M1.tail())
# print(data_time, last_time_M1)
if data_time == last_time_M1:
break
else:
trading_ins.ib.sleep(1)
# 5分足のデータも取得
df_M5 = self.get_bars_df(trade_symbol, '5 mins')
last_time_M5 = df_M5.iloc[-1]['date'].strftime('%H:%M')
# 最後の行を削除
df_M1 = df_M1[:-1]
# インジゲーターを取得する
macd_M1, signal_M1 = self.indicator(df_M1['close'].values.tolist())
macd_M5, signal_M5 = self.indicator(df_M5['close'].values.tolist())
# --------------------------------------------------------------------------
# 通知
print(macd_M5 , signal_M5)
print(macd_M1 , signal_M1)
if(
self.flag_notice == False and
macd_M5 >= signal_M5 and
macd_M1 >= signal_M1
):
line_message.put("It's a good time to trade {}.".format(trade_symbol))
self.flag_notice = True
elif(
self.flag_notice == True and
(
macd_M5 < signal_M5 or
macd_M1 < signal_M1
)
):
self.flag_notice = False
# --------------------------------------------------------------------------
# 決済
# ポジションを取得
positions = self.get_positions(trade_symbol)
if len(positions) != 0: # ポジションがあるか?
print(positions)
# 利益の確認
now_rate = self.get_tick(trade_symbol)
diff_rate = now_rate - positions['rates']
# 決済判断
print("Close Jugement!", trade_symbol, diff_rate)
if (
positions['units'] > 0 and # LONGなら
# diff_rate == diff_rate
diff_rate > PROFIT_PIPS and
(
macd_M5 < signal_M5 or
macd_M1 < signal_M1
)
):
print("Close Trading!")
# 決済
contract = CFD(trade_symbol, CFDs[trade_symbol]['EXCHANGE'], CFDs[trade_symbol]['CURRENCY']) # 銘柄 取引所 通貨
order = MarketOrder(SHORT, positions['units'])
trade_close = self.ib.placeOrder(contract, order)
# IBよりログを取得
log_status, final_units, final_rates, final_pl = self.get_log(trade_close, positions)
# 日本円に換算
if CFDs[trade_symbol]['CURRENCY'] == 'USD':
final_pl_jpy = self.get_jpy_rates(final_pl)
else:
final_pl_jpy = final_pl
# ポートフォリオを取得
portfolio, used_portfolio = self.get_portfolio()
# DBからデータを取得
db_id = db_ins.get_positions_id()
if db_id is None:
line_message.put(trade_symbol + ' was profit for {}.\nBut there was no data in DB.'.format(final_pl_jpy))
else:
print(db_id)
diff_per = diff_rate / positions['rates'] * 100
# ログの保存
trade_log = {}
trade_log['close_rates'] = final_rates
trade_log['act'] = 'profit'
trade_log['diff_per'] = diff_per
trade_log['realizedPNL'] = final_pl
trade_log['realizedPNLjpy'] = final_pl_jpy
trade_log['portfolio'] = portfolio
db_ins.insertLog(str(trade_close))
db_ins.updateTrade(trade_log, db_id)
# ポジションを初期化
positions = {}
# --------------------------------------------------------------------------
# 新規
# if len(positions) == 0:
if len(positions) == 0 and last_time_M1 == last_time_M5: # ポジションはないか? 5分刻みか?
# print("New Trading Jugement!")
# if(
# macd_M1 == macd_M1
# ):
if(
macd_M5 >= signal_M5 and
macd_M1 >= signal_M1
):
print("New Trading!")
# --------------------------------------------------------------------------
# 新規オーダー
contract = CFD(trade_symbol, CFDs[trade_symbol]['EXCHANGE'], CFDs[trade_symbol]['CURRENCY']) # 銘柄 取引所 通貨
order = MarketOrder(LONG, UNITS)
trade_new = self.ib.placeOrder(contract, order)
# ログをIBより取得
log_status, final_units, final_rates, final_pl = self.get_log(trade_new, UNITS)
print('final_rates',final_rates)
# --------------------------------------------------------------------------
# ログの保存
trade_log = {}
trade_log['symbol'] = trade_symbol
trade_log['kind'] = LONG
trade_log['units'] = UNITS
trade_log['new_rates'] = final_rates
db_ins.insertLog(str(trade_new))
db_ins.insertTrade(trade_log)
# --------------------------------------------------------------------------
# lineへの通知
messages = trade_symbol + " trade is still working today!"
if trade_close != '':
messages += "\nProfit confirmed."
if trade_new != '':
messages += "\nAnd made {} units of new trade.".format(UNITS)
line_message.put(messages)
# -------------------------------------------------------------------------
if __name__ == "__main__":
trading_ins = trading()
thread = threading.Thread(target=line_ins.queue_send_messages, args=(line_message,))
thread.start()
next_time = datetime.now(timezone(trade_timezone))
next_time = next_time.strftime('%H:%M')
while True:
try:
trading_ins.ib_connect()
while True:
# 時間の判定
now_date = datetime.now(timezone(trade_timezone))
now_time = now_date.strftime('%H:%M')
# print(now_time, next_time)
# 次の1分か?
if now_time > next_time:
next_time = now_time
# トレード種別判断
if now_time >= '01:00' and now_time < '07:10':
trade_symbol = 'IBJP225'
elif now_time >= '08:00' and now_time < '21:00':
trade_symbol = 'IBUS30'
elif now_time >= '21:00':
# 金曜日の確認
if now_date.strftime('%a') == 'Fri':
print('shut_down_time', now_date, now_date.strftime('%a'))
shut_down_flag = True
break
else:
trade_symbol = ''
# トレード
# print(now_time, trade_symbol)
if trade_symbol != '':
trading_ins.main(trade_symbol, datetime.now(timezone(data_timezone)).strftime('%H:%M'))
# スリープ
trading_ins.ib.sleep(1)
except Exception as e:
print(traceback.format_exc())
line_message.put("CFD from IB\n" + str(e))
error_count = db_ins.error_except(e, "CFD form IB", error_count)
except KeyboardInterrupt:
trading_ins.ib.disconnect()
sys.exit()
if shut_down_flag == True:
print('End of trade')
break
view raw 1-trading.py hosted with ❤ by GitHub

cls_db

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
@author: novonovo
"""
import sys
import sqlite3
import pandas as pd
import datetime
from time import sleep
from pytz import timezone
# import cls_line
ERROR_EXIT_COUNT = 3
# line_ins = cls_line.line()
class db:
def __init__(self, dbpath):
self.dbpath = dbpath
def open(self):
self.connection = sqlite3.connect(self.dbpath)
self.cursor = self.connection.cursor()
def close(self):
self.connection.close() # 接続を閉じる
def insertLog(self, messages):
print(messages)
now = datetime.datetime.now(timezone('UTC'))
try:
self.open()
sql = "INSERT INTO Log (dates,messages) VALUES (?, ?)"
self.cursor.execute(sql, (now, messages))
self.connection.commit() # 保存を実行(忘れると保存されないので注意)
self.connection.close() # 接続を閉じる
except sqlite3.Error as e:
print('sqlite3.Error occurred:', e.args[0])
return
def updateTrade(self, trade_log, id):
try:
now = datetime.datetime.now(timezone('UTC'))
self.open()
sql = ("""
UPDATE trade SET
close_date = ?,
close_rates = ?,
act = ?,
diff_per = ?,
realizedPNL = ?,
realizedPNLjpy = ?,
portfolio = ?
where id = {}
""").format(id)
self.cursor.execute(sql, (
now, trade_log['close_rates'],
trade_log['act'],
trade_log['diff_per'], trade_log['realizedPNL'], trade_log['realizedPNLjpy'],
trade_log['portfolio']
))
self.connection.commit() # 保存を実行(忘れると保存されないので注意)
self.connection.close() # 接続を閉じる
except sqlite3.Error as e:
print('sqlite3.Error occurred:', e.args[0])
def insertTrade(self, trade_log):
try:
now = datetime.datetime.now(timezone('UTC'))
self.open()
sql = """
INSERT INTO trade (
symbol, kind, units,
new_date, new_rates
) VALUES (
?, ?, ?,
?, ?
)
"""
self.cursor.execute(sql, (
trade_log['symbol'], trade_log['kind'], trade_log['units'],
now, trade_log['new_rates']
))
self.connection.commit() # 保存を実行(忘れると保存されないので注意)
self.connection.close() # 接続を閉じる
except sqlite3.Error as e:
print('sqlite3.Error occurred:', e.args[0])
# def get_won_pips(self, rowid):
# won_pips = 0
# try:
# self.open()
# sql = 'SELECT won_pips FROM trade WHERE rowid=?'
# self.cursor.execute(sql,(rowid,))
# data = self.cursor.fetchone()
# self.connection.close() # 接続を閉じる
# if data is None:
# won_pips = 0
# else:
# won_pips = float(data[0])
# except sqlite3.Error as e:
# print('sqlite3.Error occurred:', e.args[0])
# return won_pips
def get_positions_id(self):
id = None
try:
self.open()
sql = 'SELECT id FROM trade WHERE close_rates IS NULL'
self.cursor.execute(sql)
data = self.cursor.fetchone()
self.connection.close() # 接続を閉じる
# print('data', data)
if data is None:
id = None
else:
id = int(data[0])
except sqlite3.Error as e:
print('sqlite3.Error occurred:', e.args[0])
# print('id', id)
return id
# def get_positions(self):
# df = ''
# try:
# self.open()
# sql = 'SELECT id, symbol, kind, units, new_date, new_rates FROM trade WHERE close_date = ""'
# df = pd.read_sql_query(sql, self.connection)
# self.connection.close() # 接続を閉じる
# except sqlite3.Error as e:
# print('sqlite3.Error occurred:', e.args[0])
# return df
def create_db(self):
self.open()
# ログ
self.cursor.execute("DROP TABLE IF EXISTS Log")
sql = """
CREATE TABLE IF NOT EXISTS Log (
id INTEGER PRIMARY KEY AUTOINCREMENT,
dates TIMESTAMP,
messages TEXT
)
"""
self.cursor.execute(sql)
# ログ
self.cursor.execute("DROP TABLE IF EXISTS trade")
sql = """
CREATE TABLE IF NOT EXISTS trade (
id INTEGER PRIMARY KEY AUTOINCREMENT,
symbol TEXT,
kind TEXT,
units TEXT,
new_date TIMESTAMP,
new_rates REAL,
close_date TIMESTAMP,
close_rates REAL,
act TEXT,
diff_per REAL,
realizedPNL REAL,
realizedPNLjpy REAL,
portfolio REAL
)
"""
self.cursor.execute(sql)
def error_except(self, e, title, count):
messages = '=== ERROR({}) {}==='.format(count, title) + '\n'
messages += 'type:' + str(type(e)) + '\n'
messages += 'args:' + str(type(e.args)) + '\n'
messages += str(e)
self.insertLog(messages)
count += 1
sleep(1)
return count
# Not use -----------------------------------------------------------------
def readLogs_df(self):
df = pd.read_sql_query("select * from Logs", self.connection)
return df
def insertLogs(self, currency, kind, details, close_tickets):
try:
self.open()
sql = """
INSERT INTO Logs (
order_dates, close_dates, currency, turm_min, kind, units, order_rates, close_rates, diff_pips, won_pips
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
"""
self.cursor.execute(sql, [
details['order_dates'],
close_tickets['close_dates'],
currency,
close_tickets['turm_min'],
kind,
details['units'],
details['order_rates'],
close_tickets['close_rates'],
close_tickets['diff_pips'],
close_tickets['won_pips']
])
self.connection.commit() # 保存を実行(忘れると保存されないので注意)
self.connection.close() # 接続を閉じる
except sqlite3.Error as e:
print('sqlite3.Error occurred:', e.args[0])
# self.insertLog('insertLogs')
return
view raw cls_db.py hosted with ❤ by GitHub

cls_line

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
@author: novonovo
"""
# --------------------------------------------------------------------------
# ライブラリの読み込み
from time import sleep
import requests
class line:
def __init__(self):
self.url = "https://notify-api.line.me/api/notify"
self.access_token = ''
self.headers = {'Authorization': 'Bearer ' + self.access_token}
def queue_send_messages(self, line_message):
while True:
# if not line_message.empty():
message = line_message.get()
try:
payload = {'message': message}
res = requests.post(self.url, headers=self.headers, params=payload,)
if res.text == '{"status":200,"message":"ok"}':
break
except Exception as e:
print ('type:' + str(type(e)))
sleep(1)
# def send_messages(self, message):
# while True:
# try:
# payload = {'message': message}
# res = requests.post(self.url, headers=self.headers, params=payload,)
# if res.text == '{"status":200,"message":"ok"}':
# break
# except Exception as e:
# print ('type:' + str(type(e)))
# return
view raw cls_line.py hosted with ❤ by GitHub

コメント

タイトルとURLをコピーしました