自動売買BOTの中で何度も使いそうな処理を関数にまとめてみよう!

前回の記事では、CryptowatchのAPIを使って、Bitflyerの1分足の価格データ(始値と終値)を取得して表示するプログラムを書きました。

今回の記事では「関数」を勉強します。前回作った以下の処理を「自作の関数」にして後から1行で呼び出せるようにしてみましょう!

(1)CryptowatchのAPIで最新の価格を取得する処理
(2)ローソク足データの日時・始値・終値の3つを表示する処理

関数とは

関数というのは、プログラムの中で何度も登場するようなコード(処理)を1つの部品としてまとめておいて、後から1行で呼び出せるようにする記述方法のことです。

以下のように「def 関数名()」と記述することで、何度も使う処理を1つの関数にまとめることができます。

def 関数名():
	# 実行したい処理
	return x

関数名の後ろについている()は引数といいます。関数に何かデータを渡したいときは、この引数にデータを指定します。また return は、関数側からデータを外部に返したいときに使います。

また外部から関数を呼び出すときは以下のように記述します。

関数名()

具体的なコード

教科書的な説明だけ聞いても退屈でさっぱりわからないと思います。習うより慣れろです。どんどん実践用のコードを見て行きましょう!

まずは前回までのコード、つまりBitflyerから最新の1分足の価格データを取得して、日時に更新があった場合のみ表示するコードをもう1度、見ておきましょう。以下でしたね。


import requests
from datetime import datetime
import time

while True:
	
	response = requests.get("https://api.cryptowat.ch/markets/bitflyer/btcfxjpy/ohlc?periods=60")
	response = response.json()

	data = response["result"]["60"][-2]
	
	close_time = datetime.fromtimestamp(data[0]).strftime('%Y/%m/%d %H:%M')
	open_price = data[1]
	close_price = data[4]

	if close_time != last_time:
		print( "時間: " + close_time
			+ " 始値: " + str(open_price)
			+ " 終値: " + str(close_price) )
		last_time = close_time

	time.sleep(10)

ここから、(1)Cryptowatchから最新価格を取得する部分と、(2)ローソク足の日時・始値・終値を表示する部分、を関数にしてみましょう! 今回は以下のような名前の関数を2つ作ります。

・get_price()関数 … CryptowatchAPIで価格を取得
・print_price()関数 … 日時・終値・始値を表示

以下のようになります。


import requests
from datetime import datetime
import time


# Cryptowatchから 〇分足のデータを取得する関数を作成
def get_price(min):

	# APIで価格を取得する
	response = requests.get("https://api.cryptowat.ch/markets/bitflyer/btcfxjpy/ohlc",params = { "periods" : min })
	response = response.json()
	data = response["result"][str(min)][-2]
	
	close_time = data[0]
	open_price = data[1]
	close_price = data[4]

	# 日時・終値・始値の3つを返す
	return close_time, open_price, close_price


# 日時・終値・始値を表示する関数を作成
def print_price( close_time, open_price, close_price ):
	print( "時間: " + datetime.fromtimestamp(close_time).strftime('%Y/%m/%d %H:%M')
		+ " 始値: " + str(open_price)
		+ " 終値: " + str(close_price) )


# ここからがメイン処理
last_time = 0
while True:
	# get_price()関数を使って最新のローソク足の日時・始値・終値を取得する
	close_time , open_price , close_price = get_price(60)
	
	if close_time != last_time:
		last_time = close_time
		
		# print_price()関数を使って価格データを表示する
		print_price( close_time,open_price,close_price )
	
	time.sleep(10)

関数化する意味

プログラミング初心者の方は「…うん? むしろコードが長くて複雑になったぞ…?」と思うかもしれません(笑)しかし大事なのはメイン処理の部分です。

Cryptowatchから価格を取得する処理と、その内容を表示する処理、の2つを関数にして外に出したことで、今まで書いていた長いメイン処理の部分を以下のようにシンプルに7行にまとめることができました。

# ここからがメイン処理
last_time = 0
while True:
	close_time , open_price , close_price = get_price(60)
	if close_time != last_time:
		last_time = close_time
		print_price( close_time,open_price,close_price )
	time.sleep(10)

このように、ややこしい処理や何度も使う処理は、関数にして外に出しておくと、メイン処理の部分が非常に読みやすくなります。後で読み返したときに、「コード全体がどういう流れで何をやっているのか?」がわかりやすくなります。

自動売買BOTで関数を使う場面

今回はただ単にBitflyerFXのローソク足データを表示するだけなので、別に敢えて関数にする必要はありません。ですが、これが自動売買BOTになると、以下のように全体の流れも複雑になります。

1)While文でループする
2)Cryptowatchから最新価格を取得する
3)エントリー条件を判定する
4)Bitflyerにエントリー注文を出す
5)指値注文が約定したかを確認する
6)約定しなければキャンセルする
7)約定したら手仕舞いの条件を満たしたか判定する
8)手仕舞いの条件を満たしたら決済注文を出す

このような一連の流れをすべてメイン処理の中に書こうとすると、何がなんだかわからなくなります。このような場合には、

・エントリー条件を判定する関数
・サーバーに注文を出す関数
・手仕舞いの決済をする関数

など、役割ごとに関数に分けて外に出すようにしておくと、メイン処理を読みやすくシンプルに保つことができます。

コードの解説

まずは get_price()関数から見ておきましょう。
以下のように定義しています。

def get_price(min):

	# APIで価格を取得する
	response = requests.get("https://api.cryptowat.ch/markets/bitflyer/btcfxjpy/ohlc",params = { "periods" : min })
	response = response.json()
	data = response["result"][str(min)][-2]
	
	close_time = data[0]
	open_price = data[1]
	close_price = data[4]

	# 日時・終値・始値の3つを返す
	return close_time, open_price, close_price

最初の1行目の def get_price( min ) で、get_priceという関数名を使うことを定義しています。

またこの()の中にある min というのが「引数」です。このように自作の関数には、好きなデータを外部から渡すことができます。今回は、この関数を1分足、5分足、15分足でも共通で使いたいので、「何分足か?」という部分を変数にしておき、これを外部から指定できるようにしておきます。

そのため、()の中に指定した数字を受け取って、それをパラメーター( params = { “periods” : min } )に指定しています。

メイン処理で以下のように記述すれば、1分足、5分足、15分足のデータを取得できます。

# メイン処理での呼び出し

# 1分足を使う
get_price(60)

# 5分足を使う
get_price(300)

# 1時間足を使う
get_price(3600)

またこの関数には、返り値があります。それが以下の部分ですね。

	return close_time, open_price, close_price

これは 日時(close_time)、始値(open_price)、終値(close_price)の3つの値を返す、という意味です。

関数に返り値がある場合は、メイン処理の方で関数を実行したときに、この3つの返り値を受け取る変数を用意しなければなりません。以下のような具合です。

# メイン処理(呼び出す側)
# これだとエラーになる
get_price(60)

# 3つの返り値を受け取る変数を用意する。
# 何でもいい

a,b,c = get_price(60)

同じようにprint_price()のコードも見ておきましょう。

def print_price( close_time, open_price, close_price ):
	print( "時間: " + datetime.fromtimestamp(close_time).strftime('%Y/%m/%d %H:%M')
		+ " 始値: " + str(open_price)
		+ " 終値: " + str(close_price) )

こちらも def print_price() で print_price という名前の関数を作成しています。

この関数は3つの変数(日時・始値・終値)を受け取って、それをテキスト形式に変換してprintで表示するだけの関数です。返り値はありません。このように返り値のない関数も定義することができます。

返り値のない関数を呼ぶときは、メイン処理に以下のように書けばOKです。


# メイン処理(呼び出す側)
print_price(a,b,c)

このときに指定された引数を渡さないとエラーになるので注意してください。関数側で定義した引数は、必ず呼び出すときに渡さなければなりません。例えば、3つの引数が定義されているのに、メイン処理で2つしか引数を渡さない場合もエラーになります。

実行結果

これをpythonファイルに保存して実行してみましょう!
以下のようになります。

これで、何度も使う処理を関数にまとめる方法を習得することができました! 次からはいよいよ赤三兵の買いシグナルのロジックを定義して実装していきましょう!

次回記事:酒田五法の赤三兵・黒三兵の売買ロジックを作る

「自動売買BOTの中で何度も使いそうな処理を関数にまとめてみよう!」への4件のフィードバック

  1. ここ数日読ませていただいていますが大変勉強になっています。
    Pandasの.ewmを使ったEMAの関数を実装についての記事など、その他テクニカル指標についての記事も見てみたいです。(今自分がつまっているので・・・)

    1. コメントありがとうございます!了解しました!
      Pandasを使うかはわからないですが、移動平均線は必ず記事にする予定ですので、
      少しお待ちください^^

  2. botの勉強を始めました
    本当に初心者には参考になります
    close_price = last_data[4] はエラーとなりますが
    close_price = data[4] でよろしいでしょうか
    毎日少しずつ進んでいるところです
    これからもよろしくお願いします

    1. コメントありがとうございます!
      本当ですね、data[4]じゃないとおかしいです、
      ご指摘ありがとうございます!m(__)m
      こちらこそよろしくお願いします^^

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です