34
30

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

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

Last updated at Posted at 2019-06-10

#日経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倍の値段の収益となる。

#総評
良いものを作れたと思うが、思い付きの突貫工事で作成したため、かなり汚いコードとなってしまっている、、、
収益結果としては良いものを作れたと考えている。

34
30
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
34
30

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?