Skip to content

Instantly share code, notes, and snippets.

@MtkN1
Created May 5, 2023 14:54
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save MtkN1/ebd12380150cfa3d9890647dfd199241 to your computer and use it in GitHub Desktop.
Save MtkN1/ebd12380150cfa3d9890647dfd199241 to your computer and use it in GitHub Desktop.
Bybit のオーダー 1 分キャンセルロジック
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