4747logger .addHandler (handler )
4848logger .propagate = False
4949
50- ASSET_TO_SYMBOL = {"ETH" : "WETHRUSD" , "WETH" : "WETHRUSD" }
51- DEFAULT_TRANSFER_PRICE = "3156" # Realistic ETH price for transfers
50+ ASSET_TO_SYMBOL = {
51+ "ETH" : "WETHRUSD" ,
52+ "WETH" : "WETHRUSD" ,
53+ "BTC" : "WBTCRUSD" ,
54+ "WBTC" : "WBTCRUSD" ,
55+ }
56+
57+ # Mapping from asset to oracle symbol (perp symbol) for fetching oracle prices
58+ ASSET_TO_ORACLE_SYMBOL = {
59+ "ETH" : "ETHRUSDPERP" ,
60+ "WETH" : "ETHRUSDPERP" ,
61+ "BTC" : "BTCRUSDPERP" ,
62+ "WBTC" : "BTCRUSDPERP" ,
63+ }
64+
5265ORDER_SETTLEMENT_RETRIES = 3
5366ORDER_SETTLEMENT_DELAY = 1.0
5467
@@ -62,6 +75,43 @@ async def get_account_balance(client: ReyaTradingClient, account_id: int, asset:
6275 return Decimal ("0" )
6376
6477
78+ async def get_oracle_price (client : ReyaTradingClient , asset : str ) -> Decimal :
79+ """
80+ Fetch the current oracle price for an asset from the v2/prices API.
81+
82+ The oracle price is fetched from the corresponding perp market (e.g., ETHRUSDPERP for ETH).
83+ This ensures transfers happen at a price within the ±5% circuit breaker limit.
84+
85+ Args:
86+ client: ReyaTradingClient instance
87+ asset: Asset symbol (e.g., "ETH", "BTC")
88+
89+ Returns:
90+ Oracle price as Decimal
91+
92+ Raises:
93+ SystemExit: If oracle price cannot be fetched
94+ """
95+ oracle_symbol = ASSET_TO_ORACLE_SYMBOL .get (asset .upper ())
96+
97+ if not oracle_symbol :
98+ logger .error (f"❌ No oracle symbol mapping for { asset } . Supported: { list (ASSET_TO_ORACLE_SYMBOL .keys ())} " )
99+ sys .exit (1 )
100+
101+ try :
102+ price_data = await client .markets .get_price (symbol = oracle_symbol )
103+ if price_data and price_data .oracle_price :
104+ oracle_price = Decimal (price_data .oracle_price )
105+ logger .info (f"📈 Fetched oracle price for { asset } : ${ oracle_price :.2f} " )
106+ return oracle_price
107+ else :
108+ logger .error (f"❌ No oracle price returned for { oracle_symbol } " )
109+ sys .exit (1 )
110+ except (OSError , RuntimeError , ValueError ) as e :
111+ logger .error (f"❌ Failed to fetch oracle price for { oracle_symbol } : { e } " )
112+ sys .exit (1 )
113+
114+
65115async def log_account_balances (
66116 sender_client : ReyaTradingClient ,
67117 receiver_client : ReyaTradingClient | None ,
@@ -275,18 +325,21 @@ async def balance_accounts_mode() -> None:
275325 target_eth = total_eth / 2
276326 _ = total_rusd / 2 # target_rusd - calculated but not used directly
277327
328+ # Fetch current oracle price for ETH
329+ oracle_price = await get_oracle_price (client_1 , "ETH" )
330+
278331 logger .info ("🎯 TARGET ETH BALANCE" )
279332 logger .info (f" Each account: { target_eth } ETH" )
280- logger .info (f" (RUSD will flow at market price ${ DEFAULT_TRANSFER_PRICE } )" )
333+ logger .info (f" (RUSD will flow at oracle price ${ oracle_price :.2f } )" )
281334
282335 # Determine transfer direction and amounts
283336 eth_diff_1 = eth_1 - target_eth # Positive = account 1 has excess
284337
285338 # We transfer ETH from the account with excess
286- # Note: We use the market price (DEFAULT_TRANSFER_PRICE) for the transfer.
287- # This balances ETH between accounts but RUSD will flow at market price,
339+ # Note: We use the oracle price for the transfer to stay within circuit breaker .
340+ # This balances ETH between accounts but RUSD will flow at oracle price,
288341 # not at an arbitrary price to balance both assets simultaneously.
289- # On-chain price validation enforces orders must be within ~ 5% of oracle price.
342+ # On-chain price validation enforces orders must be within ± 5% of oracle price.
290343 if abs (eth_diff_1 ) < Decimal ("0.001" ):
291344 logger .info ("✅ Accounts already balanced (ETH difference < 0.001)" )
292345 return
@@ -306,8 +359,8 @@ async def balance_accounts_mode() -> None:
306359 receiver_client = client_1
307360 eth_to_transfer = - eth_diff_1
308361
309- # Use market price for transfer (on-chain enforces price limits)
310- transfer_price = Decimal ( DEFAULT_TRANSFER_PRICE )
362+ # Use oracle price for transfer (on-chain enforces ±5% price limits)
363+ transfer_price = oracle_price
311364
312365 # Round to reasonable precision
313366 eth_qty = str (eth_to_transfer .quantize (Decimal ("0.001" )))
@@ -350,7 +403,7 @@ async def main():
350403 )
351404 parser .add_argument ("--from-account" , type = int , help = "Account ID to transfer FROM (sender)" )
352405 parser .add_argument ("--to-account" , type = int , help = "Account ID to transfer TO (receiver)" )
353- parser .add_argument ("--asset" , type = str , choices = ["ETH" , "WETH" ], help = "Asset to transfer" )
406+ parser .add_argument ("--asset" , type = str , choices = ["ETH" , "WETH" , "BTC" , "WBTC" ], help = "Asset to transfer" )
354407 parser .add_argument ("--qty" , type = str , help = "Quantity to transfer (e.g., 5)" )
355408 parser .add_argument ("--price" , type = str , default = None , help = "Custom price for transfer (default: 0.01)" )
356409
@@ -370,7 +423,7 @@ async def main():
370423 to_account_id = args .to_account
371424 asset = args .asset .upper ()
372425 qty = args .qty
373- transfer_price = args .price if args . price else DEFAULT_TRANSFER_PRICE
426+ custom_price = args .price # None if not provided - will fetch oracle price dynamically
374427
375428 symbol = ASSET_TO_SYMBOL .get (asset )
376429 if not symbol :
@@ -420,7 +473,10 @@ async def main():
420473 logger .info (f" Asset: { asset } " )
421474 logger .info (f" Quantity: { qty } " )
422475 logger .info (f" Symbol: { symbol } " )
423- logger .info (f" Price: ${ transfer_price } " )
476+ if custom_price :
477+ logger .info (f" Price: ${ custom_price } (custom)" )
478+ else :
479+ logger .info (" Price: (will fetch oracle price)" )
424480
425481 # Get base config to inherit api_url and chain_id
426482 base_client = ReyaTradingClient ()
@@ -431,6 +487,15 @@ async def main():
431487 async with ReyaTradingClient (config = sender_config ) as sender_client :
432488 await sender_client .start ()
433489
490+ # Fetch oracle price if no custom price provided
491+ if custom_price :
492+ transfer_price = custom_price
493+ else :
494+ oracle_price = await get_oracle_price (sender_client , asset )
495+ # Round to 2 decimal places for transfer price
496+ transfer_price = str (oracle_price .quantize (Decimal ("0.01" )))
497+ logger .info (f" Transfer Price: ${ transfer_price } (from oracle)" )
498+
434499 # Validate sender has sufficient balance
435500 qty_decimal = Decimal (qty )
436501 if not await validate_sufficient_balance (sender_client , from_account_id , asset , qty_decimal ):
0 commit comments