Created
May 5, 2023 14:54
-
-
Save MtkN1/ebd12380150cfa3d9890647dfd199241 to your computer and use it in GitHub Desktop.
Bybit のオーダー 1 分キャンセルロジック
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import asyncio | |
import datetime | |
import itertools | |
import pybotters | |
apis = {"bybit_testnet": ["API_KEY", "API_SECRET"]} | |
TESTNET_BASE_URL = "https://api-testnet.bybit.com" | |
TESTNET_PUBLIC_WSURL = "wss://stream-testnet.bybit.com/v5/public/linear" | |
TESTNET_PRIVATE_WSURL = "wss://stream-testnet.bybit.com/v5/private" | |
SYMBOLS = ["BTCUSDT", "ETHUSDT", "SOLUSDT"] | |
PUBLIC_TOPICS = ["orderbook.1.", "tickers.", "kline.1."] | |
PRIVATE_TOPICS = ["position", "execution", "order", "wallet"] | |
async def main(): | |
""" | |
bot のメイン関数 | |
""" | |
async with pybotters.Client(apis=apis, base_url=TESTNET_BASE_URL) as client: | |
# DataStore を生成して REST API で初期化する | |
store = pybotters.BybitV5DataStore() | |
await store.initialize( | |
client.get("/v5/position/list?category=linear&settleCoin=USDT"), | |
client.get("/v5/order/realtime?category=linear&settleCoin=USDT"), | |
client.get("/v5/account/wallet-balance?accountType=CONTRACT"), | |
) | |
# Public と Private の WebSocket に接続する | |
await asyncio.gather( | |
client.ws_connect( | |
TESTNET_PUBLIC_WSURL, | |
send_json={ | |
"op": "subscribe", | |
"args": [ | |
t + s for t, s in itertools.product(PUBLIC_TOPICS, SYMBOLS) | |
], # Public のトピック名とシンボル名を組み合わせる | |
}, | |
hdlr_json=store.onmessage, | |
), | |
client.ws_connect( | |
TESTNET_PRIVATE_WSURL, | |
send_json={"op": "subscribe", "args": PRIVATE_TOPICS}, | |
hdlr_json=store.onmessage, | |
), | |
) | |
# 各種 WebSocket データが揃うまで待つ | |
while True: | |
await store.wait() | |
if all( | |
store.orderbook.find({"symbol": s}) | |
and store.ticker.find({"symbol": s}) | |
and store.kline.find({"symbol": s}) | |
for s in SYMBOLS | |
): | |
break | |
# bot メインループ | |
while True: | |
# シンボルごとのループ | |
for symbol in SYMBOLS: | |
# 各種情報を DataStore から取得する | |
orderbook = store.orderbook.sorted({"symbol": symbol}) | |
# --> {"asks": [{"price": ..., "size": ...}], "bids": [...]} | |
ticker = store.ticker.get({"symbol": symbol}) | |
# --> {"symbol": ..., "lastPrice": ...} | |
kline = store.kline.find({"symbol": symbol}) | |
# --> [{"start": ...}] | |
open_orders = store.order.find({"symbol": symbol}) | |
# --> [{"orderId": ...}] | |
# データの構造を print する (確認用) | |
print(orderbook) | |
print(ticker) | |
print(kline) | |
print(open_orders) | |
# 古いオーダーをキャンセルする | |
await cancel_orders(client, symbol, open_orders) | |
# DataStore から取得した情報から売買条件を決定する | |
# ※※※ 売買条件を実装してください ※※※ | |
cond = float(ticker["lastPrice"]) >= "○ % 以上の条件" | |
# ※※※ 売買条件を実装してください ※※※ | |
# 売買条件に真なら、オーダーを送信する | |
if cond: | |
async with client.post( | |
"/v5/order/create", | |
data={ | |
"category": "linear", | |
"symbol": symbol, | |
"side": "Buy", | |
"orderType": "Limit", | |
"qty": ..., | |
"price": ..., | |
}, | |
) as resp: | |
data = await resp.json() | |
print(data) | |
# 任意秒ごとにロジックをループする | |
await asyncio.sleep(1.0) | |
async def cancel_orders(client: pybotters.Client, symbol: str, open_orders: list): | |
""" | |
古いオーダーをキャンセルする | |
""" | |
for order in open_orders: | |
# オーダーの作成時間を計算して 1 分を超えていればキャンセルする | |
created_time = datetime.datetime.fromtimestamp(int(order["createdTime"]) / 1000) | |
now = datetime.datetime.now() | |
dt = now - created_time | |
if dt.total_seconds() > 60.0: | |
async with client.post( | |
"/v5/order/cancel", | |
data={ | |
"category": "linear", | |
"symbol": symbol, | |
"orderId": order["orderId"], | |
}, | |
) as resp: | |
data = await resp.json() | |
print(data) | |
if __name__ == "__main__": | |
try: | |
asyncio.run(main()) | |
except KeyboardInterrupt: | |
pass |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment