Python
FX
MT4
Trading
先物

Pythonで日経225先物システムトレードバックテスト


日経225先物とは

日経平均株価を元にした、指数先物取引のことで主に大阪証券取引所に上場されていて、取引時間としては、日本時間の 08:45 - 15:15、16:30 - 翌日05:30に取引される。

扱う銘柄は、日経225先物ラージなので、呼値の刻みが10円、指数の1000倍となる。

下記リンクから今回使用する過去の日経225のデータを取得することが可能

225Labo


元ネタのテクニカル

カギ足

書籍名:定本 酒田罫線法

著者:林 輝太郎

出版社: 同友館 (1991/12/1)


実装したアルゴリズム


テクニカル指標

カギ足


売買ルール


カギ足プロットルール


  1. 現在のレートをプロットする

  2. 8:50~15:00の時間内で10分区切りで終値を確認する

  3. 2.で現在のプロットから30円以上離れていたらその終値をプロットする
    ※カギ足の作成方法はここでは省きますので検索してください


買い


  1. カギ足で山を10円上回ったら買い注文

  2. 谷を10円下回ったら決済して、同時に売り注文


売り


  1. カギ足で谷を10円下回ったら売り注文

  2. 山を10円上回ったら決済して、同時に買い注文


実装したコード


10分足のシートの取得


system.py

def get10minSheet():

##プログラムが実行されたカレントディレクトリのpathを取得
print(os.getcwd())

##エクセルのファイル名を入力させる
print("please input the excel data name ->")
input_data = input()

##225データがあるパスを表示
print(os.getcwd()+ "\\" + input_data)

##225データのワークブックを取得
wb = px.load_workbook(os.getcwd()+ "\\" + input_data)

#wb = px.load_workbook("N225minif_2017.xlsx")

##10分足シートの取得
return wb["10min"]



8:50~15:00でルールを満たすものを抽出する関数


system.py

def get225Data():

##10分足のシートが返される
sheet = get10minSheet()

##カギ足グラフを画像として保存するプログラムをここに書く
#print("please input the picture name which you want to save(~.xlsx)->")
#input_save_data = input()

list1 = []
list2 = []
list3 = []
list4 = []
i = 2
count = -1
yori_flag = False
prev = 0
prev1 = 0
prev2 = 0
prev3 = 0

yori_time = datetime.time(8,50,0) ##datetimeクラスのtimeオブジェクトで保存
hike_time = datetime.time(15,0,0)
change_sq = datetime.date(2017,1,1)
change_3sq = datetime.date(2017,3,1)
change_6sq = datetime.date(2017,6,1)
change_9sq = datetime.date(2017,9,1)
change_12sq = datetime.date(2017,12,1)

while(True):
##not ~ で、~が空白文字列だったらTrueが返ってくる
if not sheet.cell(row=i,column=1).value:
break

if 1 <= sheet.cell(row=i,column=1).value.month and sheet.cell(row=i,column=1).value.month <= 3:
#8:50が始まったらフラグを立てる
if yori_time == sheet.cell(row=i,column=2).value:
yori_flag = True

if yori_flag == True and sheet.cell(row=i,column=2).value <= hike_time:
if yori_time == sheet.cell(row=i,column=2).value and abs(sheet.cell(row=i,column=3).value - prev) >= 50:
current = sheet.cell(row=i,column=3).value
n225data = Structure()
n225data.date = sheet.cell(row=i,column=1).value.date()
n225data.time = sheet.cell(row=i,column=2).value
n225data.rate = current
prev = current
current = sheet.cell(row=i,column=6).value
list1.append(n225data)
else:
current = sheet.cell(row=i,column=6).value

if abs(current - prev) >= 50:
n225data = Structure()
n225data.date = sheet.cell(row=i,column=1).value.date()
n225data.time = sheet.cell(row=i,column=2).value
n225data.rate = current
prev = current
list1.append(n225data)
else:
yori_flag = False

elif 3 < sheet.cell(row=i,column=1).value.month and sheet.cell(row=i,column=1).value.month <= 6:
#8:50が始まったらフラグを立てる
if yori_time == sheet.cell(row=i,column=2).value:
yori_flag = True

if yori_flag == True and sheet.cell(row=i,column=2).value <= hike_time:
if yori_time == sheet.cell(row=i,column=2).value and abs(sheet.cell(row=i,column=3).value - prev1) >= 50:
current1 = sheet.cell(row=i,column=3).value
n225data = Structure()
n225data.date = sheet.cell(row=i,column=1).value.date()
n225data.time = sheet.cell(row=i,column=2).value
n225data.rate = current1
prev1 = current1
current1 = sheet.cell(row=i,column=6).value
list2.append(n225data)
else:
current1 = sheet.cell(row=i,column=6).value

if abs(current1 - prev1) >= 50:
n225data = Structure()
n225data.date = sheet.cell(row=i,column=1).value.date()
n225data.time = sheet.cell(row=i,column=2).value
n225data.rate = current1
prev1 = current1
list2.append(n225data)
else:
yori_flag = False

elif 6 < sheet.cell(row=i,column=1).value.month and sheet.cell(row=i,column=1).value.month <= 9:
#8:50が始まったらフラグを立てる
if yori_time == sheet.cell(row=i,column=2).value:
yori_flag = True

if yori_flag == True and sheet.cell(row=i,column=2).value <= hike_time:
if yori_time == sheet.cell(row=i,column=2).value and abs(sheet.cell(row=i,column=3).value - prev2) >= 50:
current2 = sheet.cell(row=i,column=3).value
n225data = Structure()
n225data.date = sheet.cell(row=i,column=1).value.date()
n225data.time = sheet.cell(row=i,column=2).value
n225data.rate = current2
prev2 = current2
current2 = sheet.cell(row=i,column=6).value
list3.append(n225data)
else:
current2 = sheet.cell(row=i,column=6).value

if abs(current2 - prev2) >= 50:
n225data = Structure()
n225data.date = sheet.cell(row=i,column=1).value.date()
n225data.time = sheet.cell(row=i,column=2).value
n225data.rate = current2
prev2 = current2
list3.append(n225data)
else:
yori_flag = False

elif 9 < sheet.cell(row=i,column=1).value.month and sheet.cell(row=i,column=1).value.month <= 12:
#8:50が始まったらフラグを立てる
if yori_time == sheet.cell(row=i,column=2).value:
yori_flag = True

if yori_flag == True and sheet.cell(row=i,column=2).value <= hike_time:
if yori_time == sheet.cell(row=i,column=2).value and abs(sheet.cell(row=i,column=3).value - prev3) >= 50:
current3 = sheet.cell(row=i,column=3).value
n225data = Structure()
n225data.date = sheet.cell(row=i,column=1).value.date()
n225data.time = sheet.cell(row=i,column=2).value
n225data.rate = current3
prev3 = current3
current3 = sheet.cell(row=i,column=6).value
list4.append(n225data)
else:
current3 = sheet.cell(row=i,column=6).value

if abs(current3 - prev3) >= 50:
n225data = Structure()
n225data.date = sheet.cell(row=i,column=1).value.date()
n225data.time = sheet.cell(row=i,column=2).value
n225data.rate = current3
prev3 = current3
list4.append(n225data)
else:
yori_flag = False

i += 1

##カギ足のシグナルと損益計算
print("please input the sonnekihyou name->")
input_data_kagi = input()
entry_point1_kagi = []
entry_point2_kagi = []
entry_point3_kagi = []
entry_point4_kagi = []
kagiSignal(list1,entry_point1_kagi,input_data_kagi+"1_3"+".xlsx")
kagiSignal(list2,entry_point2_kagi,input_data_kagi+"4_6"+".xlsx")
kagiSignal(list3,entry_point3_kagi,input_data_kagi+"7_9"+".xlsx")
kagiSignal(list4,entry_point4_kagi,input_data_kagi+"10_12"+".xlsx")



売買ルール計算


system.py

def kagiSignal(list1,entry_point,save_name):

list_count = 0
retu_count = 1 #x座標のカウント
prev_list1 = Structure() #現在の1つ前の点を表す
yama_tani_queue = deque([]) #終点(山とか谷)を表すキューを作成
nuki_point = [] #山谷を抜いた瞬間のデータを列挙するリスト

yama_nuki = False #山を抜いたときにTrueになる
tani_nuki = False #谷を抜いたときにTrueになる

##このfor文は、山谷を抜いた点を抽出する部分
for w in list1:
#初期動作
if list_count == 0 and list1[0].rate > list1[1].rate:
prev_list1.rate = list1[1].rate
prev_list1.vector = -1
elif list_count == 0 and list1[0].rate < list1[1].rate:
prev_list1.rate = list1[1].rate
prev_list1.vector = 1

#初期動作を終えて3点目からスタート
if list_count >= 2:
#前の点のベクトルが1なら上昇中だから、現在値が上ならそのまま上に引くだけ(下降中でも同じ)
if prev_list1.vector == 1 and prev_list1.rate < w.rate:
prev_list1.rate = w.rate
prev_list1.vector = 1
elif prev_list1.vector == -1 and prev_list1.rate > w.rate:
prev_list1.rate = w.rate
prev_list1.vector = -1
#前の点のベクトルと現在値の方向が逆の時の処理は、列変更で山谷ができることから保存する
elif prev_list1.vector == 1 and prev_list1.rate > w.rate:
#山を格納。キューが3個になってしまうようなら、先頭を削除する
if len(yama_tani_queue) == 2:
yama_tani_queue.popleft()
yama_tani_queue.append(prev_list1)
else:
yama_tani_queue.append(prev_list1)

#現在値をprevに設定。Structureで初期化しないとqueueの中身のprevまで変わってしまう。pythonは、初期化された瞬間に新しいアドレスとなるから。
prev_list1 = Structure()
prev_list1.rate = w.rate
prev_list1.vector = -1

retu_count += 1

elif prev_list1.vector == -1 and prev_list1.rate < w.rate:
#谷を格納。キューが3個になってしまうようなら、先頭を削除する
if len(yama_tani_queue) == 2:
yama_tani_queue.popleft()
yama_tani_queue.append(prev_list1)
else:
yama_tani_queue.append(prev_list1)

prev_list1 = Structure()
prev_list1.rate = w.rate
prev_list1.vector = 1

retu_count += 1

#山谷キューが2個あるときにシグナル判定をする。
if len(yama_tani_queue) == 2:
temp = yama_tani_queue.popleft()
print(w.rate,temp.rate,temp.vector,w.rate-temp.rate,list_count)

#山を抜いたときに山を抜いたフラグをTrueにする。谷はその逆。それ以外の時は、まだシグナルが発生していないのでdequeueしたデータを戻す
if temp.vector == 1 and w.rate - temp.rate > 0:
temp3 = Structure()
yama_nuki = True
temp3.x = retu_count
temp3.rate = w.rate
temp3.date = w.date
temp3.signal = "L"
nuki_point.append(temp3)
elif temp.vector == -1 and temp.rate - w.rate > 0:
temp3 = Structure()
tani_nuki = True
temp3.x = retu_count
temp3.rate = w.rate
temp3.date = w.date
temp3.signal = "S"
nuki_point.append(temp3)
else:
yama_tani_queue.appendleft(temp)
list_count += 1

#損益表作成
make_performance(entry_point,save_name)



損益データ作成


system.py

def make_performance(entry_point,save_name):

#エクセルに書き込む用に準備する
wb2 = px.Workbook()
sheet2 = wb2.active
sheet2.title = "kagiashi"
sheet2["A1"] = "エントリー日付"
sheet2["B1"] = "エントリー"
sheet2["C1"] = "決済日付"
sheet2["D1"] = "決済"
sheet2["E1"] = "シグナル"
sheet2["F1"] = "損益"

#損益計算
column_count = 2
for i in range(1,len(entry_point)):
sonneki = 0
#if i <= len(entry_point)-1 and i+1 <= len(entry_point)-1:
sonneki = profit_loss(entry_point[i-1].rate,entry_point[i].rate,entry_point[i-1].signal)
sheet2.cell(row=column_count, column=1, value=entry_point[i-1].date)
sheet2.cell(row=column_count, column=2, value=entry_point[i-1].rate)
sheet2.cell(row=column_count, column=3, value=entry_point[i].date)
sheet2.cell(row=column_count, column=4, value=entry_point[i].rate)
sheet2.cell(row=column_count, column=5, value=entry_point[i-1].signal)
sheet2.cell(row=column_count, column=6, value=sonneki)
column_count += 1
wb2.save(save_name)



損益結果

image.png

損益結果は、縦軸が「何円幅」を表すので、miniを取引していた場合100倍の値段の収益となる。


総評

良いものを作れたと思うが、思い付きの突貫工事で作成したため、かなり汚いコードとなってしまっている、、、

収益結果としては良いものを作れたと考えている。