mirror of
https://github.com/discountry/ritmex-bot.git
synced 2026-09-09 16:28:06 +00:00
301 lines
10 KiB
Python
301 lines
10 KiB
Python
import asyncio
|
|
import os
|
|
import traceback
|
|
from datetime import datetime
|
|
from decimal import Decimal
|
|
|
|
from pysdk.grvt_ccxt_env import GrvtEnv
|
|
from pysdk.grvt_ccxt_logging_selector import logger
|
|
from pysdk.grvt_ccxt_pro import GrvtCcxtPro
|
|
from pysdk.grvt_ccxt_test_utils import validate_return_values
|
|
from pysdk.grvt_ccxt_types import DURATION_SECOND_IN_NSEC, GrvtOrderSide
|
|
from pysdk.grvt_ccxt_utils import rand_uint32
|
|
|
|
|
|
# Utility functions , not called directly by the __main__ test routine
|
|
async def get_open_orders(api: GrvtCcxtPro) -> list[dict]:
|
|
open_orders = await api.fetch_open_orders(
|
|
|
|
symbol="BTC_USDT_Perp",
|
|
params={"kind": "PERPETUAL"},
|
|
)
|
|
logger.info(f"open_orders: {open_orders=}")
|
|
return open_orders
|
|
|
|
|
|
async def fetch_order_history(api: GrvtCcxtPro) -> dict:
|
|
order_history: dict = await api.fetch_order_history(
|
|
params={"kind": "PERPETUAL", "limit": 3},
|
|
)
|
|
logger.info(f"order_history: {order_history=}")
|
|
return order_history
|
|
|
|
async def fetch_funding_history(api: GrvtCcxtPro) -> dict:
|
|
start_date: datetime = datetime.strptime("2025-05-01T00:00:00Z", "%Y-%m-%dT%H:%M:%SZ")
|
|
funding_history: dict = await api.fetch_funding_rate_history(
|
|
symbol="BTC_USDT_Perp",
|
|
since=int(start_date.timestamp() * DURATION_SECOND_IN_NSEC), # Convert to nanoseconds
|
|
limit=500,
|
|
)
|
|
results: list = funding_history.get("result", [])
|
|
if results:
|
|
logger.info(f"funding_history: START={results[0]}")
|
|
logger.info(f"funding_history: END={results[-1]}")
|
|
else:
|
|
logger.info(f"funding_history: No results found in {funding_history=}")
|
|
return funding_history
|
|
|
|
|
|
async def cancel_orders(api: GrvtCcxtPro, open_orders: list) -> int:
|
|
FN = "cancel_orders"
|
|
logger.info(f"{FN} START")
|
|
order_count: int = 0
|
|
for order_dict in open_orders:
|
|
client_order_id = order_dict["metadata"].get("client_order_id")
|
|
if client_order_id:
|
|
# Cancel
|
|
logger.info(f"{FN} cancel order by id:{order_dict['order_id']}")
|
|
await api.cancel_order(id=order_dict["order_id"])
|
|
order_count += 1
|
|
else:
|
|
logger.warning(f"{FN} client_order_id not found in {order_dict=}")
|
|
return order_count
|
|
|
|
async def show_derisk_mm_ratios(api: GrvtCcxtPro, keyword: str) -> None:
|
|
"""Show the current derisking market making ratios."""
|
|
FN = "show_derisk_mm_ratios"
|
|
acc_summary = await api.get_account_summary(type="sub-account")
|
|
maintenance_margin = acc_summary.get("maintenance_margin")
|
|
derisk_margin = acc_summary.get("derisk_margin")
|
|
derisk_ratio = acc_summary.get("derisk_to_maintenance_margin_ratio")
|
|
logger.info(f"{FN} {keyword} {maintenance_margin=}")
|
|
logger.info(f"{FN} {keyword} {derisk_margin=}")
|
|
logger.info(f"{FN} {keyword} {derisk_ratio=}")
|
|
logger.info(f"sub-account summary:\n{acc_summary}")
|
|
|
|
async def set_derisk_mm_ratio(api: GrvtCcxtPro, ratio: str = "1.5") -> None:
|
|
"""Set the derisking market making ratio."""
|
|
FN = f"set_derisk_mm_ratio {ratio=}"
|
|
logger.info(f"{FN} START")
|
|
await show_derisk_mm_ratios(api, "BEFORE")
|
|
await api.set_derisk_mm_ratio(ratio)
|
|
await show_derisk_mm_ratios(api, "AFTER")
|
|
|
|
async def cancel_all_orders(api: GrvtCcxtPro) -> bool:
|
|
FN = "cancel_all_orders"
|
|
logger.info(f"{FN} START")
|
|
cancel_response = await api.cancel_all_orders()
|
|
logger.info(f"{FN} {cancel_response=}")
|
|
return cancel_response
|
|
|
|
|
|
async def print_instruments(api: GrvtCcxtPro):
|
|
logger.info("print_instruments: START")
|
|
if not api.markets:
|
|
return
|
|
for market in list(api.markets.values())[:3]:
|
|
logger.info(f"{market=}")
|
|
instrument = market["instrument"]
|
|
logger.info(f"fetch_mini_ticker: {instrument=}, {await api.fetch_mini_ticker(instrument)}")
|
|
logger.info(f"fetch_ticker: {instrument=}, {await api.fetch_ticker(instrument)}")
|
|
logger.info(
|
|
f"fetch_order_book {instrument=}, {await api.fetch_order_book(instrument, limit=10)}"
|
|
)
|
|
logger.info(
|
|
f"fetch_recent_trades {instrument=}, "
|
|
f"{await api.fetch_recent_trades(instrument, limit=7)}"
|
|
)
|
|
logger.info(f"fetch_trades {instrument=}, {await api.fetch_trades(instrument, limit=5)}")
|
|
logger.info(
|
|
f"fetch_funding_rate_history {instrument=}, "
|
|
f"{await api.fetch_funding_rate_history(instrument, limit=5)}"
|
|
)
|
|
for type in ["TRADE", "MARK", "INDEX", "MID"]:
|
|
ohlc = await api.fetch_ohlcv(
|
|
instrument, timeframe="1m", limit=5, params={"candle_type": type}
|
|
)
|
|
logger.info(f"fetch_ohlcv {type} {instrument=}, {ohlc}")
|
|
|
|
|
|
async def send_order(api: GrvtCcxtPro, side: GrvtOrderSide, client_order_id: int) -> dict:
|
|
price = 64_000 if side == "buy" else 65_000
|
|
send_order_response = await api.create_order(
|
|
symbol="BTC_USDT_Perp",
|
|
order_type="limit",
|
|
side=side,
|
|
amount=0.01,
|
|
price=price,
|
|
params={"client_order_id": client_order_id},
|
|
)
|
|
logger.info(f"send order: {send_order_response=} {client_order_id=}")
|
|
return send_order_response
|
|
|
|
|
|
# Test scenarios, called by the __main__ test routine
|
|
async def send_fetch_order(api: GrvtCcxtPro):
|
|
client_order_id = rand_uint32()
|
|
_ = await send_order(api, side="buy", client_order_id=client_order_id)
|
|
order_status = await api.fetch_order(
|
|
id=None,
|
|
params={"client_order_id": client_order_id},
|
|
)
|
|
logger.info(f"result of fetch_order: {order_status=}")
|
|
|
|
|
|
async def send_mkt_order(
|
|
api: GrvtCcxtPro, symbol: str, side: GrvtOrderSide, amount: Decimal, client_order_id: int
|
|
) -> dict:
|
|
send_order_response = await api.create_order(
|
|
symbol=symbol,
|
|
order_type="market",
|
|
side=side,
|
|
amount=amount,
|
|
params={"client_order_id": client_order_id},
|
|
)
|
|
logger.info(f"send mkt order: {send_order_response=} {client_order_id=}")
|
|
return send_order_response
|
|
|
|
|
|
async def check_cancel_check_orders(api: GrvtCcxtPro):
|
|
logger.info("check_cancel_check_orders: START")
|
|
open_orders = await get_open_orders(api)
|
|
if open_orders:
|
|
await cancel_orders(api, open_orders)
|
|
await get_open_orders(api)
|
|
|
|
|
|
async def fetch_my_trades(api: GrvtCcxtPro):
|
|
logger.info("fetch_my_trades: START")
|
|
my_trades = await api.fetch_my_trades(
|
|
symbol="BTC_USDT_Perp",
|
|
limit=10,
|
|
params={},
|
|
)
|
|
logger.info(f"my_trades: num trades:{len(my_trades)}")
|
|
logger.info(f"my_trades: {my_trades=}")
|
|
|
|
|
|
async def cancel_send_order(api: GrvtCcxtPro):
|
|
FN = "cancel_send_order"
|
|
logger.info(f"{FN}: START")
|
|
client_order_id: int = rand_uint32()
|
|
logger.info(f"{FN} cancel order by {client_order_id=}")
|
|
result = await api.cancel_order(
|
|
params={"client_order_id": client_order_id, "time_to_live_ms": "1000"}
|
|
)
|
|
logger.info(f"{FN} cancel_order: {result=}")
|
|
order_response = await send_mkt_order(
|
|
api,
|
|
symbol="BTC_USDT_Perp",
|
|
side="sell",
|
|
amount=Decimal("0.01"),
|
|
client_order_id=client_order_id,
|
|
)
|
|
if order_response:
|
|
# Get status
|
|
logger.info(f"{FN} fetch_order by {client_order_id=}")
|
|
order_status = await api.fetch_order(params={"client_order_id": client_order_id})
|
|
logger.info(f"{FN} {order_status=}")
|
|
|
|
|
|
async def print_markets(api: GrvtCcxtPro):
|
|
logger.info("print_markets: START")
|
|
if api.markets:
|
|
logger.info(f"MARKETS:{len(api.markets)}")
|
|
for market in api.markets.values():
|
|
logger.info(f"MARKET:{market}")
|
|
|
|
|
|
async def fetch_all_markets(api: GrvtCcxtPro):
|
|
logger.info("fetch_all_markets: START")
|
|
instruments = await api.fetch_all_markets()
|
|
logger.info(f"fetch_all_markets: num instruments={len(instruments)}")
|
|
|
|
|
|
async def print_account_summary(api: GrvtCcxtPro):
|
|
try:
|
|
logger.info("print_account_summary: START")
|
|
logger.info(f"sub-account summary:\n{await api.get_account_summary(type='sub-account')}")
|
|
logger.info(f"funding-account summary:\n{await api.get_account_summary(type='funding')}")
|
|
logger.info(
|
|
f"aggregated-account summary:\n{await api.get_account_summary(type='aggregated')}"
|
|
)
|
|
logger.info(f"fetch_balance:\n{await api.fetch_balance()}")
|
|
except Exception as e:
|
|
logger.error(f"account summary failed: {e}")
|
|
|
|
|
|
async def print_account_history(api: GrvtCcxtPro):
|
|
try:
|
|
hist = await api.fetch_account_history(params={})
|
|
logger.info(f"account history:\n{hist}")
|
|
except Exception as e:
|
|
logger.error(f"account history failed: {e}")
|
|
|
|
|
|
async def print_positions(api: GrvtCcxtPro):
|
|
try:
|
|
logger.info(f"positions:\n{await api.fetch_positions(symbols=['BTC_USDT_Perp'])}")
|
|
except Exception as e:
|
|
logger.error(f"positions failed: {e}")
|
|
|
|
|
|
async def print_description(api: GrvtCcxtPro):
|
|
try:
|
|
logger.info(f"print_description: {api.describe()}")
|
|
except Exception as e:
|
|
logger.error(f"print_description failed: {e}")
|
|
|
|
|
|
async def grvt_ccxt_pro():
|
|
params = {
|
|
"api_key": os.getenv("GRVT_API_KEY"),
|
|
"trading_account_id": os.getenv("GRVT_TRADING_ACCOUNT_ID"),
|
|
"private_key": os.getenv("GRVT_PRIVATE_KEY"),
|
|
}
|
|
env = GrvtEnv(os.getenv("GRVT_ENV", "testnet"))
|
|
test_api = GrvtCcxtPro(env, logger, parameters=params, order_book_ccxt_format=True)
|
|
await test_api.load_markets()
|
|
await asyncio.sleep(2)
|
|
function_list = [
|
|
print_description,
|
|
# -------- MARKET related
|
|
fetch_all_markets,
|
|
print_markets,
|
|
print_instruments,
|
|
print_account_summary,
|
|
print_account_history,
|
|
print_positions,
|
|
# Order / Trade history
|
|
fetch_my_trades,
|
|
fetch_order_history,
|
|
fetch_funding_history,
|
|
# Trade related
|
|
send_fetch_order,
|
|
check_cancel_check_orders,
|
|
fetch_my_trades,
|
|
fetch_order_history,
|
|
print_positions,
|
|
cancel_send_order,
|
|
get_open_orders,
|
|
send_fetch_order,
|
|
get_open_orders,
|
|
cancel_all_orders,
|
|
get_open_orders,
|
|
set_derisk_mm_ratio,
|
|
]
|
|
for f in function_list:
|
|
try:
|
|
await f(test_api)
|
|
except Exception as e:
|
|
logger.error(f"Error in {f.__name__}: {e} {traceback.format_exc()}")
|
|
validate_return_values(test_api, "test_results.csv")
|
|
|
|
|
|
def test_grvt_ccxt_pro() -> None:
|
|
asyncio.run(grvt_ccxt_pro())
|
|
|
|
|
|
if __name__ == "__main__":
|
|
test_grvt_ccxt_pro()
|