前回の記事に引き続き、今回も仮想通貨botの開発状況をまとめていきます。
参考にしたのは【Botter Advent Calendar2023】仮想通貨で月に1万円を稼ぐC級Botterになろうです。
ccxtライブラリ、少しずつ分かってきました。 pic.twitter.com/E9PwAf7p1b
— よだか(夜鷹/yodaka) (@yodakablog) January 17, 2024
また、今回は「現在の価格とは何をもってそのように定義するのか?」という点についても掘り下げることができました。
参考にしたのは2-4."現在価格"の考察です。
【サイト紹介】
高頻度やるbotterは一回は見といた方がいい記事です。現在の価格はいくらなのかを研究している記事です。現在価格は常に変化するもので、それをより正確に把握できているかどうかは高頻度botの利益に影響してきます。https://t.co/KX2r1acrn4— あいば (@aiba_algorithm) January 19, 2024
ccxtライブラリを参照してChatGPTと共にコードを書く
今回は例題1に取り組みました。
例題1:fetchOrderBookを使って任意の取引所(現物)のETH-USDT価格を取得しましょう
例題2: 今、0.01ethを任意のperpがある取引所でロングしているとします。例えば、Kucoin futuresのETH-USDTMにポジションがあるとします。
fetchPositions fetch_balance を用いて、ロング/ショートをどの程度持っているか表示し、フリーなUSDTバランスをprintで表示させましょう。
例題 3: createOrderを用いて0.01 ethを購入し、10秒後に売却しましょう。レバは3倍とし、market orderを使用しましょう。
下準備⓪:取引クラスのインスタンス化
ccxtライブラリは、さまざまな仮想通貨取引所と通信するためのPythonライブラリであり、各取引所に対応するクラスを提供しています。これらのクラスは、取引所のAPIにアクセスするためのメソッドや機能を提供しています。
取引所クラスをインスタンス化するとは、その取引所にアクセスするための具体的なオブジェクトを作成することを指します。これにより、その取引所と対話できるようになります。
もう少し簡単に言うと「取引クラスのインスタンス化」とは
その取引所のAPIにアクセスでき、取引や市場データの取得などさまざまな操作を行う準備
のことです。
簡単な例を見てみましょう。
import ccxt
# 取引所クラスをインスタンス化する例
exchange = ccxt.binance({
'apiKey': 'your_api_key',
'secret': 'your_secret_key',
})
# 取引所の情報を取得
symbol = 'BTC/USDT'
ticker = exchange.fetch_ticker(symbol)
print(ticker)
この例では、Binance取引所のクラス(ccxt.binance)をインスタンス化しています。この取引所クラスにはBinance APIにアクセスするためのキー情報が渡されています。その後、fetch_tickerメソッドを使用して指定された通貨ペア('BTC/USDT')の最新の価格情報を取得しています。
このようにしてccxtライブラリでさまざまな操作を行う下準備をします。
下準備①:リストの取得
ccxtがサポートしている取引所の一覧を取得します。
#ccxtでサポートされている取引所のリストを取得 import ccxt from pprint import pprint#見やすくするためにpprintを使用 pprint (ccxt.exchanges)

下準備②:トークンペアのリストの取得
任意の取引所で取引可能なトークンペアのリストを取得します。
import ccxt
def get_exchange_symbols(exchange_name):
try:
# 取引所のインスタンスを作成
exchange = getattr(ccxt, exchange_name)()
# 取引所のシンボル(トークンのペア)を取得
symbols = exchange.load_markets().keys()
return symbols
except ccxt.NetworkError as e:
print(f"Network error: {e}")
except ccxt.ExchangeError as e:
print(f"Exchange error: {e}")
except Exception as e:
print(f"An error occurred: {e}")
# 取引所の名前(KuCoinの場合は 'kucoin' を指定)
exchange_name = 'kucoin'
# 取引所のシンボル(トークンのペア)を取得
symbols = get_exchange_symbols(exchange_name)
# 結果を表示
print(f"{exchange_name}の取引可能なシンボル(トークンのペア):")
for symbol in symbols:
print(symbol)

実際にこのコードを実行すると、とても長いリストが延々と並ぶことになります。表示される量が膨大で分かりにくいため、コードを修正することにしました。
取引可能なトークンペアの検出
その取引所で扱うトークンペアの有無を調べるためのコードを書かせました。
import ccxt
def check_token_pair(exchange_name, base_currency, quote_currency):
try:
# 取引所のインスタンスを作成
exchange = getattr(ccxt, exchange_name)()
# 取引所のシンボル(トークンのペア)を取得
symbols = exchange.load_markets().keys()
# 検証したいトークンのペア
target_pair = f"{base_currency}/{quote_currency}"
# 検証したいトークンのペアが取引所で取引可能かどうかを検出
is_pair_available = target_pair in symbols
# 結果を表示
if is_pair_available:
print(f"{exchange_name}で{target_pair}は取引可能です。")
else:
print(f"{exchange_name}で{target_pair}は取引不可能です。")
except ccxt.NetworkError as e:
print(f"Network error: {e}")
except ccxt.ExchangeError as e:
print(f"Exchange error: {e}")
except Exception as e:
print(f"An error occurred: {e}")
# 取引所の名前(KuCoinの場合は 'kucoin' を指定)
exchange_name = 'kucoin'
# 検証したいトークンのベース通貨とクォート通貨を指定
base_currency = 'BTC'
quote_currency = 'USDT'
# トークンのペアが取引所で取引可能かどうかを検出
check_token_pair(exchange_name, base_currency, quote_currency)

コード終盤の「検証したいトークンのベース通貨とクォート通貨を指定」の部分に指定の通貨シンボルを入力すると「その取引所で取引可能な通貨ペアかどうか」を調べることができます。
例題1の回答
練習:fetch_ticker
まずは、Tickerを参照する場合は、以下のコードで価格を取得してみました。
fetch_tickerメソッドを使います。
指定するのはsymbolだけなので、シンプルで分かりやすいですね。
#Tickerを参照して現物取引価格を取得
import ccxt
# 取引所クラスをインスタンス化する
exchange = ccxt.binance({
'apiKey': '***',
'secret': '***',
})
# 取引所の情報を取得
symbol = 'ETH/USDT'
ticker = exchange.fetch_ticker(symbol)
print(ticker)

本題:fetch_order_book
次に、例題2につなげることを意識してkucoinでの価格取得用コードを書きました。
MMBot開発につなげることを見越して、Bid/Ask/スプレッドを取得しています。
import ccxt
exchange = ccxt.kucoin()#任意の取引所を設定
symbol = 'ETH/USDT'
# マーケット情報をロード
exchange.load_markets()
# 取引ペアが存在するか確認
if symbol in exchange.symbols:
orderbook = exchange.fetch_order_book(symbol)
bid = orderbook['bids'][0][0] if len(orderbook['bids']) > 0 else None
ask = orderbook['asks'][0][0] if len(orderbook['asks']) > 0 else None
spread = (ask - bid) if (bid and ask) else None
print(exchange.id, 'market price', {'bid': bid, 'ask': ask, 'spread': spread})
else:
print(f"Symbol {symbol} not found.")

load_marketを使わない場合は以下のような書き方もできます。
import ccxt
# KuCoinの取引所を初期化
exchange = ccxt.kucoin()
# マーケットとシンボルを指定 (例: ETH/USDT)
symbol = 'ETH/USDT'
# fetchOrderBookを使ってETH-USDTの価格情報を取得
order_book = exchange.fetch_order_book(symbol)
# ベストビッドとベストアスクの価格を表示
best_bid_price = order_book['bids'][0][0]
best_ask_price = order_book['asks'][0][0]
print(f'KuCoin ETH/USDT - Best Bid Price: {best_bid_price}, Best Ask Price: {best_ask_price}')

主に参考にしたのはccxtドキュメントの以下の部分です。
market-price:現在の最良の価格(クエリ市場価格)を取得し,ビッド/アスク/スプレッドを計算する。
Loading Markets:ccxtを迂回して、取引所からデータを取得する。→通信の負担が減ってBotの速度が上がる。
Order Book:板情報の取得。ビッド(買い)価格とアスク(売り)価格、出来高、その他のデータを含むオープン注文に関する情報。市場の深さ。取引の意思決定プロセス。
「現在の価格とは?」
「現在の価格」という概念が私にとって非常に曖昧だったので、勉強しました。
執行する戦略のタイプに応じて現在の価格の定義は変わるということが分かりました。
改めて読み直してみました。「実装する戦略のタイプに応じて必要な見方が変わる」という点は必ず押さえておきます。この記事、有益なのでマインドマップ作ります。
2-4."現在価格"の考察|piyopiyotch @piyopiyotch #note https://t.co/pCFOH8p543
— よだか(夜鷹/yodaka) (@yodakablog) January 20, 2024

参考記事
【宿題】
・MMbotを作る際には取引所の仕様を「板情報・Ticker・約定」の3観点でデータを比較して研究する
・使用する取引所やモジュールの仕様が書いてあるドキュメントを読み込む(取得している価格データは何を参照したものなのかを確認する)
・Bot稼働ログのデータ分析で何を確認したいのかを明確にする
例題1の回答:番外編(ChatGPT)
ChatGPTにも出力させてみました。少しだけ修正を加えています。
【Binance用】
#例題1:fetchOrderBookを使って任意の取引所(現物)のETH-USDT価格を取得しましょう
import ccxt
# Binanceの取引所を初期化
exchange = ccxt.binance({
'apiKey': binance_api_key,
'secret': binance_secret_key,
})
# マーケットとシンボルを指定
symbol = 'ETH/USDT'
# fetchOrderBookを使ってETH-USDTの価格情報を取得
order_book = exchange.fetch_order_book(symbol)
# ベストビッドとベストアスクの価格を表示
best_bid_price = order_book['bids'][0][0]
best_ask_price = order_book['asks'][0][0]
print(f'Binance ETH/USDT - Best Bid Price: {best_bid_price}, Best Ask Price: {best_ask_price}')

【Kucoin用】
import ccxt
# KuCoinの取引所を初期化
exchange = ccxt.kucoin({
'apiKey': kucoin_api_key,
'secret': kucoin_secret_key,
})
# マーケットとシンボルを指定 (例: ETH/USDT)
symbol = 'ETH/USDT'
# fetchOrderBookを使ってETH-USDTの価格情報を取得
order_book = exchange.fetch_order_book(symbol)
# ベストビッドとベストアスクの価格を表示
best_bid_price = order_book['bids'][0][0]
best_ask_price = order_book['asks'][0][0]
print(f'KuCoin ETH/USDT - Best Bid Price: {best_bid_price}, Best Ask Price: {best_ask_price}')

ちなみにChatGPTに回答させると、最初はAPIキーとAPIシークレットの入力も含めたコードで返してきました。しかし、パブリックAPIを利用する場合はAPIキーとAPIシークレットの両方とも必要ないため、それを指摘すると改善したコードを返してきました。
基本的な理解が伴っていないと、AIが書いたコードをそのまま使うことになってしまうため、ドキュメントの熟読は必須だなと感じた瞬間でした。

何に関してもだけど、ある程度の事以上をやろうとする(といっても入門レベル)と断片的にサクッとググるより、ちゃんと公式なドキュメントに目を通した方が結局早い
— まちゅけん@pybotters (@MtkN1XBt) January 18, 2024
価格取得の方法:基本+5種(Binance用)
最後に「ccxtライブラリを使って任意の取引所(この例ではBinance)からETH-USDT価格を取得する方法」をまとめておきます。今後の執行戦略によって使い分けていこうと思います。
基本:Tickerメソッドを使用して情報を取得する方法
#Tickerを参照して現物取引価格を取得
import ccxt
# 取引所クラスをインスタンス化する例
exchange = ccxt.binance({
'apiKey': '***',
'secret': '***',
})
# 取引所の情報を取得
symbol = 'ETH/USDT'
ticker = exchange.fetch_ticker(symbol)
print(ticker)
import ccxt: ccxtライブラリをインポートする。exchange = ccxt.binance({'apiKey': '***', 'secret': '***'}): BinanceのAPIキーとシークレットキーを使用して、Binance取引所のクラスをインスタンス化する。このクラスはBinanceとの通信を可能にします。symbol = 'ETH/USDT': 取得したい通貨ペアを指定する。この例ではETH(イーサリアム)とUSDT(Tether)の組み合わせです。ticker = exchange.fetch_ticker(symbol): 指定された通貨ペアの最新のticker情報を取得する。ticker情報には、現在の価格や過去の取引量などが含まれる。print(ticker): 取得したticker情報をコンソールに表示する。これにより、最新の価格や取引に関する情報が表示される。

このコードを実行するためには、BinanceのAPIキーとシークレットキーが必要です。
①fetch_marketsメソッドを使用してマーケット一覧を取得する方法
import ccxt
# 任意の取引所クラスをインスタンス化
exchange = ccxt.binance() # 例: Binanceを選択
# マーケット一覧を取得
markets = exchange.fetch_markets()
# ETH-USDTのマーケット情報を検索
eth_usdt_market = next((market for market in markets if market['symbol'] == 'ETH/USDT'), None)
if eth_usdt_market:
# 価格の取得
ticker = exchange.fetch_ticker(eth_usdt_market['symbol'])
print(ticker)
else:
print("ETH/USDT market not found.")
この方法では、fetch_tickerメソッドにsymbol引数を指定して、ETH-USDTの価格情報を取得します。取引所によっては通貨ペアの表記が異なることがあるため、適切な通貨ペアを指定する必要があります。

②load_marketsメソッドを使用してmarketsディクショナリを取得する方法
import ccxt # 任意の取引所クラスをインスタンス化 exchange = ccxt.binance() # 例: Binanceを選択 # マーケット情報をロード markets = exchange.load_markets() # ETH-USDTのマーケット情報を取得 eth_usdt_market = markets['ETH/USDT'] # 価格の取得 ticker = exchange.fetch_ticker(eth_usdt_market['symbol']) # 結果の表示 print(ticker)
この方法では、load_marketsメソッドを使用して取引所のマーケット情報をロードし、ETH-USDTのマーケット情報を取得します。その後、取引所のfetch_tickerメソッドに適切なsymbolを渡して価格を取得します。

③fetch_tickersメソッドを使用して全ての価格情報を取得する方法
import ccxt # 任意の取引所クラスをインスタンス化 exchange = ccxt.binance() # 例: Binanceを選択 # 全ての価格情報を取得 tickers = exchange.fetch_tickers() # ETH-USDTの価格情報を取得 eth_usdt_ticker = tickers['ETH/USDT'] # 結果の表示 print(eth_usdt_ticker)
この方法では、fetch_tickersメソッドを使用して全ての通貨ペアの価格情報を取得し、その中からETH-USDTの価格情報を取り出します。

④fetch_order_bookメソッドを使用して板情報を取得する方法
import ccxt
# 任意の取引所クラスをインスタンス化
exchange = ccxt.binance() # 例: Binanceを選択
# ETH-USDTの板情報を取得
order_book = exchange.fetch_order_book('ETH/USDT')
# 最良の買い気配と売り気配の価格を表示
print("Best Bid Price:", order_book['bids'][0][0])
print("Best Ask Price:", order_book['asks'][0][0])
この方法では、fetch_order_bookメソッドを使用してETH-USDTの板情報を取得し、最良の買い気配価格と売り気配価格を表示します。

⑤fetchOHLCVメソッドを使用してローソク足データを取得する方法
#fetchOHLCVメソッドを使用してローソク足データを取得する方法
import ccxt
from datetime import datetime
# 任意の取引所クラスをインスタンス化
exchange = ccxt.binance() # 例: Binanceを選択
# ETH-USDTのローソク足データを取得
ohlcv = exchange.fetch_ohlcv('ETH/USDT', timeframe='1h', limit=1)
if ohlcv:
# 最新のローソク足データを表示
latest_candle = ohlcv[0]
timestamp, open, high, low, close, volume = latest_candle
date = datetime.fromtimestamp(timestamp / 1000.0)
# 各項目を表示
print(f"Timestamp: {timestamp}")
print(f"Date: {date}")
print(f"Open Price: {open}")
print(f"High Price: {high}")
print(f"Low Price: {low}")
print(f"Close Price: {close}")
print(f"Volume: {volume}")
else:
print("No OHLCV data available.")
この方法では、fetch_ohlcvメソッドを使用してETH-USDTの指定した時間枠のローソク足データを取得します。上記の例では1時間足の最新のローソク足データを表示しています。

参考箇所
CCXTドキュメント:Public API
まとめ
「C級Botterになろう」の例題で「任意の取引所の現物価格を取得する」というものに取り組んでいる時に「何をもって(現在の)価格とするのだろう?」という疑問があったのですが解決しました。
執行する戦略によって答えが変わるのですね。
分類できてスッキリしました。
また、ChatGPTにコードを書かせてその根拠を公式ドキュメントから探すという方法も有効だと気が付きました。
この調子で学習を進めていきます。
【宿題】
①やり方が分からなかったら、とりあえずChatGPTにコードを書かせてその根拠を公式ドキュメントから探す
②もう一度自分の手でコードを書く