mirror of
https://github.com/discountry/ritmex-bot.git
synced 2026-09-09 16:28:06 +00:00
265 lines
8.5 KiB
Python
265 lines
8.5 KiB
Python
import json
|
|
import time
|
|
from typing import Dict, Any, Optional, List, Union
|
|
from decimal import Decimal
|
|
|
|
from .internal.async_client import AsyncClient
|
|
from .internal.signing_adapter import SigningAdapter
|
|
from .internal.starkex_signing_adapter import StarkExSigningAdapter
|
|
from .account.client import Client as AccountClient
|
|
from .asset.client import Client as AssetClient
|
|
from .funding.client import Client as FundingClient
|
|
from .metadata.client import Client as MetadataClient
|
|
from .order.client import Client as OrderClient
|
|
from .quote.client import Client as QuoteClient
|
|
from .transfer.client import Client as TransferClient
|
|
from .order.types import CreateOrderParams, CancelOrderParams, GetActiveOrderParams, OrderFillTransactionParams
|
|
|
|
|
|
class Client:
|
|
"""Main EdgeX SDK client."""
|
|
|
|
def __init__(self, base_url: str, account_id: int, stark_private_key: str,
|
|
signing_adapter: Optional[SigningAdapter] = None, timeout: float = 30.0):
|
|
"""
|
|
Initialize the EdgeX SDK client.
|
|
|
|
Args:
|
|
base_url: Base URL for API endpoints
|
|
account_id: Account ID for authentication
|
|
stark_private_key: Stark private key for signing
|
|
signing_adapter: Optional signing adapter (defaults to StarkExSigningAdapter)
|
|
timeout: Request timeout in seconds
|
|
"""
|
|
# Use StarkExSigningAdapter as default if none provided
|
|
if signing_adapter is None:
|
|
signing_adapter = StarkExSigningAdapter()
|
|
|
|
# Create async client
|
|
self.async_client = AsyncClient(
|
|
base_url=base_url,
|
|
account_id=account_id,
|
|
stark_pri_key=stark_private_key,
|
|
signing_adapter=signing_adapter,
|
|
timeout=timeout
|
|
)
|
|
|
|
# Initialize API clients
|
|
self.metadata = MetadataClient(self.async_client)
|
|
self.account = AccountClient(self.async_client)
|
|
self.order = OrderClient(self.async_client)
|
|
self.quote = QuoteClient(self.async_client)
|
|
self.funding = FundingClient(self.async_client)
|
|
self.transfer = TransferClient(self.async_client)
|
|
self.asset = AssetClient(self.async_client)
|
|
|
|
async def __aenter__(self):
|
|
"""Async context manager entry."""
|
|
await self.async_client._ensure_session()
|
|
return self
|
|
|
|
async def __aexit__(self, exc_type, exc_val, exc_tb):
|
|
"""Async context manager exit."""
|
|
await self.close()
|
|
|
|
async def close(self):
|
|
"""Close the client and cleanup resources."""
|
|
await self.async_client.close()
|
|
|
|
@property
|
|
def internal_client(self):
|
|
"""Backward compatibility property for accessing internal client."""
|
|
return self.async_client
|
|
|
|
async def get_metadata(self) -> Dict[str, Any]:
|
|
"""Get the exchange metadata."""
|
|
return await self.metadata.get_metadata()
|
|
|
|
async def get_server_time(self) -> Dict[str, Any]:
|
|
"""Get the current server time."""
|
|
return await self.metadata.get_server_time()
|
|
|
|
async def create_order(self, params: CreateOrderParams) -> Dict[str, Any]:
|
|
"""
|
|
Create a new order with the given parameters.
|
|
|
|
Args:
|
|
params: Order parameters
|
|
|
|
Returns:
|
|
Dict[str, Any]: The created order
|
|
"""
|
|
# Get metadata first
|
|
metadata = await self.get_metadata()
|
|
if not metadata:
|
|
raise ValueError("failed to get metadata")
|
|
|
|
return await self.order.create_order(params, metadata.get("data", {}))
|
|
|
|
async def get_max_order_size(self, contract_id: str, price: Decimal) -> Dict[str, Any]:
|
|
"""
|
|
Get the maximum order size for a given contract and price.
|
|
|
|
Args:
|
|
contract_id: The contract ID
|
|
price: The price
|
|
|
|
Returns:
|
|
Dict[str, Any]: The maximum order size information
|
|
"""
|
|
return await self.order.get_max_order_size(contract_id, float(price))
|
|
|
|
async def cancel_order(self, params: CancelOrderParams) -> Dict[str, Any]:
|
|
"""
|
|
Cancel a specific order.
|
|
|
|
Args:
|
|
params: Cancel order parameters
|
|
|
|
Returns:
|
|
Dict[str, Any]: The cancellation result
|
|
"""
|
|
return await self.order.cancel_order(params)
|
|
|
|
async def get_active_orders(self, params: GetActiveOrderParams) -> Dict[str, Any]:
|
|
"""
|
|
Get active orders with pagination and filters.
|
|
|
|
Args:
|
|
params: Active order query parameters
|
|
|
|
Returns:
|
|
Dict[str, Any]: The active orders
|
|
"""
|
|
return await self.order.get_active_orders(params)
|
|
|
|
async def get_order_fill_transactions(self, params: OrderFillTransactionParams) -> Dict[str, Any]:
|
|
"""
|
|
Get order fill transactions with pagination and filters.
|
|
|
|
Args:
|
|
params: Order fill transaction query parameters
|
|
|
|
Returns:
|
|
Dict[str, Any]: The order fill transactions
|
|
"""
|
|
return await self.order.get_order_fill_transactions(params)
|
|
|
|
async def get_account_asset(self) -> Dict[str, Any]:
|
|
"""Get the account asset information."""
|
|
return await self.account.get_account_asset()
|
|
|
|
async def get_account_positions(self) -> Dict[str, Any]:
|
|
"""Get the account positions."""
|
|
return await self.account.get_account_positions()
|
|
|
|
async def create_limit_order(
|
|
self,
|
|
contract_id: str,
|
|
size: str,
|
|
price: str,
|
|
side: str,
|
|
client_order_id: Optional[str] = None
|
|
) -> Dict[str, Any]:
|
|
"""
|
|
Create a new limit order with the given parameters.
|
|
|
|
Args:
|
|
contract_id: The contract ID
|
|
size: The order size
|
|
price: The order price
|
|
side: The order side (BUY or SELL)
|
|
client_order_id: Optional client order ID
|
|
|
|
Returns:
|
|
Dict[str, Any]: The created order
|
|
"""
|
|
from .order.types import OrderType
|
|
|
|
params = CreateOrderParams(
|
|
contract_id=contract_id,
|
|
size=size,
|
|
price=price,
|
|
side=side,
|
|
type=OrderType.LIMIT,
|
|
client_order_id=client_order_id
|
|
)
|
|
|
|
return await self.create_order(params)
|
|
|
|
async def create_market_order(
|
|
self,
|
|
contract_id: str,
|
|
size: str,
|
|
side: str,
|
|
client_order_id: Optional[str] = None
|
|
) -> Dict[str, Any]:
|
|
"""
|
|
Create a new market order with the given parameters.
|
|
|
|
Args:
|
|
contract_id: The contract ID
|
|
size: The order size
|
|
side: The order side (BUY or SELL)
|
|
client_order_id: Optional client order ID
|
|
|
|
Returns:
|
|
Dict[str, Any]: The created order
|
|
"""
|
|
# Get metadata for contract info
|
|
metadata = await self.get_metadata()
|
|
if not metadata:
|
|
raise ValueError("failed to get metadata")
|
|
|
|
# Find the contract
|
|
contract = None
|
|
contract_list = metadata.get("data", {}).get("contractList", [])
|
|
for c in contract_list:
|
|
if c.get("contractId") == contract_id:
|
|
contract = c
|
|
break
|
|
|
|
if not contract:
|
|
raise ValueError(f"contract not found: {contract_id}")
|
|
|
|
# Calculate price based on side
|
|
from .order.types import OrderSide, OrderType
|
|
|
|
if side == OrderSide.BUY:
|
|
# For buy orders: oracle_price * 10, rounded to price precision
|
|
quote = await self.get_24_hour_quote(contract_id)
|
|
if not quote:
|
|
raise ValueError("failed to get 24-hour quotes")
|
|
|
|
oracle_price = Decimal(quote.get("data", [])[0].get("oraclePrice", "0"))
|
|
multiplier = Decimal("10")
|
|
tick_size = Decimal(contract.get("tickSize", "0"))
|
|
precision = abs(tick_size.as_tuple().exponent)
|
|
price = str(round(oracle_price * multiplier, precision))
|
|
else:
|
|
# For sell orders: use tick size
|
|
price = contract.get("tickSize", "0")
|
|
|
|
params = CreateOrderParams(
|
|
contract_id=contract_id,
|
|
size=size,
|
|
price=price,
|
|
side=side,
|
|
type=OrderType.MARKET,
|
|
client_order_id=client_order_id
|
|
)
|
|
|
|
return await self.create_order(params)
|
|
|
|
async def get_24_hour_quote(self, contract_id: str) -> Dict[str, Any]:
|
|
"""
|
|
Get the 24-hour quotes for a given contract.
|
|
|
|
Args:
|
|
contract_id: The contract ID
|
|
|
|
Returns:
|
|
Dict[str, Any]: The 24-hour quotes
|
|
"""
|
|
return await self.quote.get_24_hour_quote(contract_id)
|