|
@@ -40,7 +40,8 @@ def add_state_flow_entry(process_item, state_name, msg, status_val="pending"):
|
|
|
|
|
|
|
|
class ArbitrageProcess:
|
|
class ArbitrageProcess:
|
|
|
def __init__(self, tx, gas_limit_multiplier, gas_price_multiplier,
|
|
def __init__(self, tx, gas_limit_multiplier, gas_price_multiplier,
|
|
|
- from_token, to_token, from_token_amount_human, out_token_amount_human,
|
|
|
|
|
|
|
+ from_token, to_token,
|
|
|
|
|
+ from_token_amount_human, exchange_out_amount,
|
|
|
user_exchange_wallet, user_wallet,
|
|
user_exchange_wallet, user_wallet,
|
|
|
symbol, process_item):
|
|
symbol, process_item):
|
|
|
"""
|
|
"""
|
|
@@ -71,33 +72,33 @@ class ArbitrageProcess:
|
|
|
self.process_item = process_item
|
|
self.process_item = process_item
|
|
|
|
|
|
|
|
# 存储当前套利交易的细节信息,例如买入数量、价格等
|
|
# 存储当前套利交易的细节信息,例如买入数量、价格等
|
|
|
- chain_usdt_use = Decimal(from_token_amount_human)
|
|
|
|
|
self.arbitrage_details = {
|
|
self.arbitrage_details = {
|
|
|
- "chain_buy_tx_hash": None, # 链上买入的tx hash
|
|
|
|
|
- "chain_usdt_use": chain_usdt_use, # 链上usdt减少量(使用量), todo, 暂用固定值代替
|
|
|
|
|
- "out_token_amount_human": out_token_amount_human, # 链上可能会产生的out数量,交易所的代币剩余量一定要大于这个值
|
|
|
|
|
|
|
+ "chain_buy_tx_hash": None, # 链上买入的tx hash
|
|
|
|
|
+ "chain_usdt_use": Decimal(from_token_amount_human), # 链上usdt减少量(使用量), todo, 暂用固定值代替
|
|
|
"chain_amount_before_trade": 0,
|
|
"chain_amount_before_trade": 0,
|
|
|
"chain_amount_after_trade": 0,
|
|
"chain_amount_after_trade": 0,
|
|
|
- "chain_buy_amount": Decimal('0'), # 链上币增加量(购入量), todo, 暂用即时余额代替
|
|
|
|
|
- "chain_buy_price": None, # 链上购入价, todo
|
|
|
|
|
- "chain_withdrawal_tx_hash": None, # 链上转入交易所的tx
|
|
|
|
|
- "exchange_sell_order_id": None, # 交易所卖出id
|
|
|
|
|
- "exchange_withdraw_id": None, # 交易所提现id
|
|
|
|
|
- "exchange_withdraw_amount": None, # 交易所提现数量
|
|
|
|
|
|
|
+ "chain_buy_amount": Decimal('0'), # 链上币增加量(购入量), todo, 暂用即时余额代替
|
|
|
|
|
+ "chain_buy_price": None, # 链上购入价, todo
|
|
|
|
|
+ "chain_withdrawal_tx_hash": None, # 链上转入交易所的tx
|
|
|
|
|
+ "exchange_out_amount": Decimal(exchange_out_amount), # 交易所卖出量
|
|
|
|
|
+ "exchange_sell_order_id": None, # 交易所卖出id
|
|
|
|
|
+ "exchange_withdraw_id": None, # 交易所提现id
|
|
|
|
|
+ "exchange_withdraw_amount": None, # 交易所提现数量
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
# 定义可能的状态
|
|
# 定义可能的状态
|
|
|
self.STATES = [
|
|
self.STATES = [
|
|
|
|
|
+ "SELLING_ON_EXCHANGE", # 正在中心化交易所卖出现货
|
|
|
|
|
+ "WAITING_SELL_CONFIRM", # 等待现货卖出订单确认
|
|
|
"BUYING_ON_CHAIN", # 正在链上买入
|
|
"BUYING_ON_CHAIN", # 正在链上买入
|
|
|
"WAITING_CHAIN_CONFIRM", # 等待链上交易确认
|
|
"WAITING_CHAIN_CONFIRM", # 等待链上交易确认
|
|
|
|
|
+ "WAITING_EXCHANGE_ROLLBACK", # 等待交易所回滚
|
|
|
# "HEDGING_ON_EXCHANGE", # 正在中心化交易所套保
|
|
# "HEDGING_ON_EXCHANGE", # 正在中心化交易所套保
|
|
|
# "WAITING_HEDGE_CONFIRM", # 等待套保订单确认
|
|
# "WAITING_HEDGE_CONFIRM", # 等待套保订单确认
|
|
|
- "TRANSFERRING_TO_EXCHANGE", # 正在向交易所转账
|
|
|
|
|
- "WAITING_TRANSFER_ARRIVE", # 等待交易所充值到账
|
|
|
|
|
- "SELLING_ON_EXCHANGE", # 正在中心化交易所卖出现货
|
|
|
|
|
- "WAITING_SELL_CONFIRM", # 等待现货卖出订单确认
|
|
|
|
|
|
|
+ # "TRANSFERRING_TO_EXCHANGE", # 正在向交易所转账
|
|
|
# "CLOSING_HEDGE", # 正在平掉套保单
|
|
# "CLOSING_HEDGE", # 正在平掉套保单
|
|
|
# "WAITING_CLOSE_HEDGE_CONFIRM", # 等待平掉套保单确认
|
|
# "WAITING_CLOSE_HEDGE_CONFIRM", # 等待平掉套保单确认
|
|
|
|
|
+ "WAITING_TRANSFER_ARRIVE", # 等待交易所充值到账
|
|
|
"TRANSFERRING_TO_CHAIN", # 正在向链上转账
|
|
"TRANSFERRING_TO_CHAIN", # 正在向链上转账
|
|
|
"WAITING_WITHDRAWAL_CONFIRM", # 等待链上提现确认
|
|
"WAITING_WITHDRAWAL_CONFIRM", # 等待链上提现确认
|
|
|
"COMPLETED", # 套利流程完成
|
|
"COMPLETED", # 套利流程完成
|
|
@@ -105,12 +106,13 @@ class ArbitrageProcess:
|
|
|
]
|
|
]
|
|
|
|
|
|
|
|
self.STATE_IDLE = "IDLE"
|
|
self.STATE_IDLE = "IDLE"
|
|
|
|
|
+ self.STATE_SELLING_ON_EXCHANGE = "SELLING_ON_EXCHANGE"
|
|
|
|
|
+ self.STATE_WAITING_SELL_CONFIRM = "WAITING_SELL_CONFIRM"
|
|
|
self.STATE_BUYING_ON_CHAIN = "BUYING_ON_CHAIN"
|
|
self.STATE_BUYING_ON_CHAIN = "BUYING_ON_CHAIN"
|
|
|
self.STATE_WAITING_CHAIN_CONFIRM = "WAITING_CHAIN_CONFIRM"
|
|
self.STATE_WAITING_CHAIN_CONFIRM = "WAITING_CHAIN_CONFIRM"
|
|
|
- self.STATE_TRANSFERRING_TO_EXCHANGE = "TRANSFERRING_TO_EXCHANGE"
|
|
|
|
|
|
|
+ self.STATE_WAITING_EXCHANGE_ROLLBACK = "WAITING_EXCHANGE_ROLLBACK"
|
|
|
|
|
+ # self.STATE_TRANSFERRING_TO_EXCHANGE = "TRANSFERRING_TO_EXCHANGE"
|
|
|
self.STATE_WAITING_TRANSFER_ARRIVE = "WAITING_TRANSFER_ARRIVE"
|
|
self.STATE_WAITING_TRANSFER_ARRIVE = "WAITING_TRANSFER_ARRIVE"
|
|
|
- self.STATE_SELLING_ON_EXCHANGE = "SELLING_ON_EXCHANGE"
|
|
|
|
|
- self.STATE_WAITING_SELL_CONFIRM = "WAITING_SELL_CONFIRM"
|
|
|
|
|
self.STATE_TRANSFERRING_TO_CHAIN = "TRANSFERRING_TO_CHAIN"
|
|
self.STATE_TRANSFERRING_TO_CHAIN = "TRANSFERRING_TO_CHAIN"
|
|
|
self.STATE_WAITING_WITHDRAWAL_CONFIRM = "WAITING_WITHDRAWAL_CONFIRM"
|
|
self.STATE_WAITING_WITHDRAWAL_CONFIRM = "WAITING_WITHDRAWAL_CONFIRM"
|
|
|
self.STATE_COMPLETED = "COMPLETED"
|
|
self.STATE_COMPLETED = "COMPLETED"
|
|
@@ -134,20 +136,27 @@ class ArbitrageProcess:
|
|
|
根据当前状态执行套利流程的下一步
|
|
根据当前状态执行套利流程的下一步
|
|
|
这是一个周期性调用的函数,例如在主循环中调用
|
|
这是一个周期性调用的函数,例如在主循环中调用
|
|
|
"""
|
|
"""
|
|
|
- if self.current_state == "BUYING_ON_CHAIN":
|
|
|
|
|
|
|
+
|
|
|
|
|
+ if self.current_state == "SELLING_ON_EXCHANGE":
|
|
|
|
|
+ self._execute_sell_on_exchange()
|
|
|
|
|
+
|
|
|
|
|
+ elif self.current_state == "WAITING_SELL_CONFIRM":
|
|
|
|
|
+ self._wait_sell_confirm()
|
|
|
|
|
+
|
|
|
|
|
+ elif self.current_state == "BUYING_ON_CHAIN":
|
|
|
self._execute_buy_on_chain()
|
|
self._execute_buy_on_chain()
|
|
|
|
|
|
|
|
elif self.current_state == "WAITING_CHAIN_CONFIRM":
|
|
elif self.current_state == "WAITING_CHAIN_CONFIRM":
|
|
|
self._wait_chain_confirm()
|
|
self._wait_chain_confirm()
|
|
|
|
|
|
|
|
|
|
+ elif self.current_state == "WAITING_EXCHANGE_ROLLBACK":
|
|
|
|
|
+ self._wait_exchange_rollback()
|
|
|
|
|
+
|
|
|
# elif self.current_state == "TRANSFERRING_TO_EXCHANGE":
|
|
# elif self.current_state == "TRANSFERRING_TO_EXCHANGE":
|
|
|
# self._execute_transfer_to_exchange()
|
|
# self._execute_transfer_to_exchange()
|
|
|
|
|
|
|
|
- elif self.current_state == "SELLING_ON_EXCHANGE":
|
|
|
|
|
- self._execute_sell_on_exchange()
|
|
|
|
|
-
|
|
|
|
|
- elif self.current_state == "WAITING_SELL_CONFIRM":
|
|
|
|
|
- self._wait_sell_confirm()
|
|
|
|
|
|
|
+ elif self.current_state == "WAITING_TRANSFER_ARRIVE":
|
|
|
|
|
+ self._wait_transfer_arrive()
|
|
|
|
|
|
|
|
elif self.current_state == "TRANSFERRING_TO_CHAIN":
|
|
elif self.current_state == "TRANSFERRING_TO_CHAIN":
|
|
|
self._execute_transfer_to_chain()
|
|
self._execute_transfer_to_chain()
|
|
@@ -155,9 +164,6 @@ class ArbitrageProcess:
|
|
|
elif self.current_state == "WAITING_WITHDRAWAL_CONFIRM":
|
|
elif self.current_state == "WAITING_WITHDRAWAL_CONFIRM":
|
|
|
self._wait_withdrawal_confirm()
|
|
self._wait_withdrawal_confirm()
|
|
|
|
|
|
|
|
- elif self.current_state == "WAITING_TRANSFER_ARRIVE":
|
|
|
|
|
- self._wait_transfer_arrive()
|
|
|
|
|
-
|
|
|
|
|
elif self.current_state == "COMPLETED":
|
|
elif self.current_state == "COMPLETED":
|
|
|
msg = "套利流程成功完成!"
|
|
msg = "套利流程成功完成!"
|
|
|
logging.info(msg)
|
|
logging.info(msg)
|
|
@@ -168,28 +174,32 @@ class ArbitrageProcess:
|
|
|
logging.info(msg)
|
|
logging.info(msg)
|
|
|
add_state_flow_entry(self.process_item, self.current_state, msg, "fail")
|
|
add_state_flow_entry(self.process_item, self.current_state, msg, "fail")
|
|
|
|
|
|
|
|
- # 以下是每个状态对应的具体执行函数(伪代码)
|
|
|
|
|
-
|
|
|
|
|
- def _execute_buy_on_chain(self):
|
|
|
|
|
|
|
+ # 以下是每个状态对应的具体执行函数
|
|
|
|
|
+ def _execute_sell_on_exchange(self):
|
|
|
"""
|
|
"""
|
|
|
- 在链上执行买入操作
|
|
|
|
|
|
|
+ 在中心化交易所卖出现货
|
|
|
"""
|
|
"""
|
|
|
- msg = "执行:链上买入操作..."
|
|
|
|
|
|
|
+ msg = "执行:中心化交易所卖出现货..."
|
|
|
logging.info(msg)
|
|
logging.info(msg)
|
|
|
add_state_flow_entry(self.process_item, self.current_state, msg, "pending")
|
|
add_state_flow_entry(self.process_item, self.current_state, msg, "pending")
|
|
|
try:
|
|
try:
|
|
|
|
|
+ # 第一步直接卖出,这个数量用固定数量
|
|
|
|
|
+ pseudo_amount_to_sell = self.arbitrage_details["exchange_out_amount"]
|
|
|
|
|
+ # 处理精度
|
|
|
|
|
+ pseudo_amount_to_sell = pseudo_amount_to_sell.quantize(Decimal('1'), rounding=ROUND_DOWN)
|
|
|
|
|
+
|
|
|
# 交易所套保余额判断
|
|
# 交易所套保余额判断
|
|
|
balances = mexc.trade.get_account_info()['balances']
|
|
balances = mexc.trade.get_account_info()['balances']
|
|
|
for balance in balances:
|
|
for balance in balances:
|
|
|
if balance['asset'] == self.coin:
|
|
if balance['asset'] == self.coin:
|
|
|
- if Decimal(balance['free']) < Decimal(self.arbitrage_details['out_token_amount_human']):
|
|
|
|
|
- msg = f"交易所剩余{self.coin}: {balance['free']}, 链上预计购入:{self.arbitrage_details['out_token_amount_human']}, 不能触发套保交易。"
|
|
|
|
|
|
|
+ if Decimal(balance['free']) < pseudo_amount_to_sell:
|
|
|
|
|
+ msg = f"交易所剩余{self.coin}: {balance['free']}, 交易所准备卖出:{pseudo_amount_to_sell}, 不能触发套保交易。"
|
|
|
logging.info(msg)
|
|
logging.info(msg)
|
|
|
add_state_flow_entry(self.process_item, self.current_state, msg, "fail")
|
|
add_state_flow_entry(self.process_item, self.current_state, msg, "fail")
|
|
|
self._set_state(self.STATE_FAILED)
|
|
self._set_state(self.STATE_FAILED)
|
|
|
return
|
|
return
|
|
|
else:
|
|
else:
|
|
|
- msg = f"交易所剩余{self.coin}: {balance['free']}, 链上预计购入:{self.arbitrage_details['out_token_amount_human']}, 余额校验通过(可以套保)。"
|
|
|
|
|
|
|
+ msg = f"交易所剩余{self.coin}: {balance['free']}, 交易所准备卖出:{pseudo_amount_to_sell}, 余额校验通过(可以套保)。"
|
|
|
logging.info(msg)
|
|
logging.info(msg)
|
|
|
add_state_flow_entry(self.process_item, self.current_state, msg, "success")
|
|
add_state_flow_entry(self.process_item, self.current_state, msg, "success")
|
|
|
break
|
|
break
|
|
@@ -205,7 +215,88 @@ class ArbitrageProcess:
|
|
|
msg = f"链上剩余{self.base_coin}: {from_token_balance}, 需要使用:{self.arbitrage_details["chain_usdt_use"]}, 余额充足。"
|
|
msg = f"链上剩余{self.base_coin}: {from_token_balance}, 需要使用:{self.arbitrage_details["chain_usdt_use"]}, 余额充足。"
|
|
|
logging.info(msg)
|
|
logging.info(msg)
|
|
|
add_state_flow_entry(self.process_item, self.current_state, msg, "success")
|
|
add_state_flow_entry(self.process_item, self.current_state, msg, "success")
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
|
|
+ order_params = {
|
|
|
|
|
+ "symbol": self.symbol.replace('_', ''),
|
|
|
|
|
+ "side": "SELL",
|
|
|
|
|
+ "type": "MARKET",
|
|
|
|
|
+ "quantity": int(pseudo_amount_to_sell),
|
|
|
|
|
+ }
|
|
|
|
|
+ logging.info(order_params)
|
|
|
|
|
+ exchange_sell_order = mexc.trade.post_order(order_params)
|
|
|
|
|
+ if 'orderId' not in exchange_sell_order:
|
|
|
|
|
+ msg = f"交易所现货卖出下单失败:{exchange_sell_order}"
|
|
|
|
|
+ logging.error(msg)
|
|
|
|
|
+ add_state_flow_entry(self.process_item, self.current_state, msg, "fail")
|
|
|
|
|
+ self._set_state("FAILED")
|
|
|
|
|
+
|
|
|
|
|
+ return
|
|
|
|
|
+
|
|
|
|
|
+ exchange_sell_order_id = exchange_sell_order['orderId']
|
|
|
|
|
+
|
|
|
|
|
+ msg = f"交易所现货卖出订单已发送, 订单ID: {exchange_sell_order_id}"
|
|
|
|
|
+ logging.info(msg)
|
|
|
|
|
+ add_state_flow_entry(self.process_item, self.current_state, msg, "success")
|
|
|
|
|
+
|
|
|
|
|
+ self.arbitrage_details["exchange_sell_order_id"] = exchange_sell_order_id
|
|
|
|
|
+ self._set_state(self.STATE_WAITING_SELL_CONFIRM)
|
|
|
|
|
+ except Exception as e:
|
|
|
|
|
+ logging.error(f"交易所现货卖出下单失败:{e}")
|
|
|
|
|
+ self._set_state("FAILED")
|
|
|
|
|
+
|
|
|
|
|
+ def _wait_sell_confirm(self):
|
|
|
|
|
+ """
|
|
|
|
|
+ 等待交易所现货卖出订单确认(完全成交)
|
|
|
|
|
+ """
|
|
|
|
|
+ exchange_sell_order_id = self.arbitrage_details["exchange_sell_order_id"]
|
|
|
|
|
+ msg = f"等待交易所现货卖出订单确认:{exchange_sell_order_id}"
|
|
|
|
|
+ logging.info(msg)
|
|
|
|
|
+ add_state_flow_entry(self.process_item, self.current_state, msg, "pending")
|
|
|
|
|
+ try:
|
|
|
|
|
+ # 查询交易所订单状态
|
|
|
|
|
+ waiting_times = 30
|
|
|
|
|
+ while True:
|
|
|
|
|
+ params = {
|
|
|
|
|
+ "symbol": self.symbol.replace('_', ''),
|
|
|
|
|
+ "orderId": exchange_sell_order_id
|
|
|
|
|
+ }
|
|
|
|
|
+ order = mexc.trade.get_order(params)
|
|
|
|
|
+
|
|
|
|
|
+ if order['status'] == "FILLED":
|
|
|
|
|
+ money = Decimal(order['cummulativeQuoteQty'])
|
|
|
|
|
+ amount = self.arbitrage_details["exchange_out_amount"]
|
|
|
|
|
+ price = money / amount
|
|
|
|
|
+ price = price.quantize(Decimal('1e-8'), rounding=ROUND_DOWN)
|
|
|
|
|
+
|
|
|
|
|
+ msg = f"交易所现货卖出订单已完全成交, 价格:{price}。{order}"
|
|
|
|
|
+ self.arbitrage_details["exchange_withdraw_amount"] = order['cummulativeQuoteQty']
|
|
|
|
|
+
|
|
|
|
|
+ logging.info(msg)
|
|
|
|
|
+ add_state_flow_entry(self.process_item, self.current_state, msg, "success")
|
|
|
|
|
+
|
|
|
|
|
+ self._set_state(self.STATE_BUYING_ON_CHAIN)
|
|
|
|
|
+ return
|
|
|
|
|
+ else:
|
|
|
|
|
+ # 继续等待成交
|
|
|
|
|
+ pass
|
|
|
|
|
+
|
|
|
|
|
+ time.sleep(1)
|
|
|
|
|
+ waiting_times = waiting_times - 1
|
|
|
|
|
+
|
|
|
|
|
+ except Exception as e:
|
|
|
|
|
+ msg = f"查询交易所现货卖出订单状态时发生错误:{e}"
|
|
|
|
|
+ logging.error(msg)
|
|
|
|
|
+ add_state_flow_entry(self.process_item, self.current_state, msg, "fail")
|
|
|
|
|
+ self._set_state("FAILED")
|
|
|
|
|
+
|
|
|
|
|
+ def _execute_buy_on_chain(self):
|
|
|
|
|
+ """
|
|
|
|
|
+ 在链上执行买入操作
|
|
|
|
|
+ """
|
|
|
|
|
+ msg = "执行:链上买入操作..."
|
|
|
|
|
+ logging.info(msg)
|
|
|
|
|
+ add_state_flow_entry(self.process_item, self.current_state, msg, "pending")
|
|
|
|
|
+ try:
|
|
|
self.arbitrage_details["chain_amount_before_trade"] = web3.get_erc20_balance(self.to_token_addr, self.user_exchange_wallet)
|
|
self.arbitrage_details["chain_amount_before_trade"] = web3.get_erc20_balance(self.to_token_addr, self.user_exchange_wallet)
|
|
|
# 调用链上客户端执行买入交易
|
|
# 调用链上客户端执行买入交易
|
|
|
chain_buy_tx_hash = web3._sign_and_send_transaction(
|
|
chain_buy_tx_hash = web3._sign_and_send_transaction(
|
|
@@ -225,7 +316,7 @@ class ArbitrageProcess:
|
|
|
msg = f"链上买入失败:{e}"
|
|
msg = f"链上买入失败:{e}"
|
|
|
logging.error(msg)
|
|
logging.error(msg)
|
|
|
add_state_flow_entry(self.process_item, self.current_state, msg, "fail")
|
|
add_state_flow_entry(self.process_item, self.current_state, msg, "fail")
|
|
|
- self._set_state("FAILED")
|
|
|
|
|
|
|
+ self._set_state(self.STATE_WAITING_EXCHANGE_ROLLBACK)
|
|
|
|
|
|
|
|
def _wait_chain_confirm(self):
|
|
def _wait_chain_confirm(self):
|
|
|
"""
|
|
"""
|
|
@@ -256,86 +347,95 @@ class ArbitrageProcess:
|
|
|
msg = f"链上交易已确认。用{sell_amount_human}买入{buy_amount_human},价格{price_human}。"
|
|
msg = f"链上交易已确认。用{sell_amount_human}买入{buy_amount_human},价格{price_human}。"
|
|
|
logging.info(msg)
|
|
logging.info(msg)
|
|
|
add_state_flow_entry(self.process_item, self.current_state, msg, "success")
|
|
add_state_flow_entry(self.process_item, self.current_state, msg, "success")
|
|
|
- self._set_state(self.STATE_SELLING_ON_EXCHANGE)
|
|
|
|
|
|
|
+ self._set_state(self.STATE_WAITING_TRANSFER_ARRIVE)
|
|
|
else:
|
|
else:
|
|
|
msg = f"链上交易确认失败:{hash}"
|
|
msg = f"链上交易确认失败:{hash}"
|
|
|
logging.error(msg)
|
|
logging.error(msg)
|
|
|
add_state_flow_entry(self.process_item, self.current_state, msg, "fail")
|
|
add_state_flow_entry(self.process_item, self.current_state, msg, "fail")
|
|
|
- self._set_state("FAILED")
|
|
|
|
|
|
|
+ self._set_state(self.STATE_WAITING_EXCHANGE_ROLLBACK)
|
|
|
|
|
|
|
|
except Exception as e:
|
|
except Exception as e:
|
|
|
msg = f"查询链上确认状态时发生错误:{e}"
|
|
msg = f"查询链上确认状态时发生错误:{e}"
|
|
|
logging.error(msg)
|
|
logging.error(msg)
|
|
|
add_state_flow_entry(self.process_item, self.current_state, msg, "fail")
|
|
add_state_flow_entry(self.process_item, self.current_state, msg, "fail")
|
|
|
- self._set_state("FAILED")
|
|
|
|
|
|
|
+ self._set_state(self.STATE_WAITING_EXCHANGE_ROLLBACK)
|
|
|
|
|
|
|
|
- def _execute_sell_on_exchange(self):
|
|
|
|
|
|
|
+ def _wait_exchange_rollback(self):
|
|
|
"""
|
|
"""
|
|
|
- 在中心化交易所卖出现货
|
|
|
|
|
|
|
+ 市价进行交易所交易回滚
|
|
|
"""
|
|
"""
|
|
|
- msg = "执行:中心化交易所卖出现货..."
|
|
|
|
|
|
|
+ msg = "执行:中心化交易所买入现货回滚..."
|
|
|
logging.info(msg)
|
|
logging.info(msg)
|
|
|
add_state_flow_entry(self.process_item, self.current_state, msg, "pending")
|
|
add_state_flow_entry(self.process_item, self.current_state, msg, "pending")
|
|
|
try:
|
|
try:
|
|
|
- pseudo_amount_to_sell = self.arbitrage_details["chain_buy_amount"]
|
|
|
|
|
- # pseudo_amount_to_sell = Decimal('200000')
|
|
|
|
|
|
|
+ # 使用预提现数量进行回滚
|
|
|
|
|
+ pseudo_amount_to_buy = self.arbitrage_details["exchange_withdraw_amount"]
|
|
|
# 处理精度
|
|
# 处理精度
|
|
|
- pseudo_amount_to_sell = pseudo_amount_to_sell.quantize(Decimal('1'), rounding=ROUND_DOWN)
|
|
|
|
|
|
|
+ pseudo_amount_to_buy = pseudo_amount_to_buy.quantize(Decimal('1'), rounding=ROUND_DOWN)
|
|
|
|
|
+
|
|
|
|
|
+ # 交易所U余额判断
|
|
|
|
|
+ balances = mexc.trade.get_account_info()['balances']
|
|
|
|
|
+ for balance in balances:
|
|
|
|
|
+ if balance['asset'] == self.base_coin:
|
|
|
|
|
+ pseudo_amount_to_buy = min(Decimal(balance['free']), pseudo_amount_to_buy)
|
|
|
|
|
+
|
|
|
|
|
+ if pseudo_amount_to_buy < Decimal('10'):
|
|
|
|
|
+ msg = f"交易所剩余{self.base_coin}: {balance['free']}, 小于10, 不能触发回滚交易。"
|
|
|
|
|
+ logging.info(msg)
|
|
|
|
|
+ add_state_flow_entry(self.process_item, self.current_state, msg, "fail")
|
|
|
|
|
+ self._set_state(self.STATE_FAILED)
|
|
|
|
|
+ return
|
|
|
|
|
+ else:
|
|
|
|
|
+ msg = f"交易所剩余{self.base_coin}: {balance['free']}, 交易所准备使用:{pseudo_amount_to_buy}, 余额校验通过(可以回滚)。"
|
|
|
|
|
+ logging.info(msg)
|
|
|
|
|
+ add_state_flow_entry(self.process_item, self.current_state, msg, "success")
|
|
|
|
|
+ break
|
|
|
|
|
|
|
|
order_params = {
|
|
order_params = {
|
|
|
"symbol": self.symbol.replace('_', ''),
|
|
"symbol": self.symbol.replace('_', ''),
|
|
|
- "side": "SELL",
|
|
|
|
|
|
|
+ "side": "BUY",
|
|
|
"type": "MARKET",
|
|
"type": "MARKET",
|
|
|
- "quantity": int(pseudo_amount_to_sell),
|
|
|
|
|
|
|
+ "quoteOrderQty": int(pseudo_amount_to_buy),
|
|
|
}
|
|
}
|
|
|
logging.info(order_params)
|
|
logging.info(order_params)
|
|
|
- exchange_sell_order = mexc.trade.post_order(order_params)
|
|
|
|
|
- if 'orderId' not in exchange_sell_order:
|
|
|
|
|
- msg = f"交易所现货卖出下单失败:{exchange_sell_order}"
|
|
|
|
|
|
|
+ exchange_buy_order = mexc.trade.post_order(order_params)
|
|
|
|
|
+ if 'orderId' not in exchange_buy_order:
|
|
|
|
|
+ msg = f"【回滚】交易所现货买入下单失败:{exchange_buy_order}"
|
|
|
logging.error(msg)
|
|
logging.error(msg)
|
|
|
add_state_flow_entry(self.process_item, self.current_state, msg, "fail")
|
|
add_state_flow_entry(self.process_item, self.current_state, msg, "fail")
|
|
|
self._set_state("FAILED")
|
|
self._set_state("FAILED")
|
|
|
|
|
|
|
|
return
|
|
return
|
|
|
|
|
|
|
|
- exchange_sell_order_id = exchange_sell_order['orderId']
|
|
|
|
|
|
|
+ exchange_buy_order_id = exchange_buy_order['orderId']
|
|
|
|
|
|
|
|
- msg = f"交易所现货卖出订单已发送, 订单ID: {exchange_sell_order_id}"
|
|
|
|
|
|
|
+ msg = f"【回滚】交易所现货买入订单已发送, 订单ID: {exchange_buy_order_id}"
|
|
|
logging.info(msg)
|
|
logging.info(msg)
|
|
|
add_state_flow_entry(self.process_item, self.current_state, msg, "success")
|
|
add_state_flow_entry(self.process_item, self.current_state, msg, "success")
|
|
|
|
|
|
|
|
- self.arbitrage_details["exchange_sell_order_id"] = exchange_sell_order_id
|
|
|
|
|
- self._set_state(self.STATE_WAITING_SELL_CONFIRM)
|
|
|
|
|
- except Exception as e:
|
|
|
|
|
- logging.error(f"交易所现货卖出下单失败:{e}")
|
|
|
|
|
- self._set_state("FAILED")
|
|
|
|
|
-
|
|
|
|
|
- def _wait_sell_confirm(self):
|
|
|
|
|
- """
|
|
|
|
|
- 等待交易所现货卖出订单确认(完全成交)
|
|
|
|
|
- """
|
|
|
|
|
- exchange_sell_order_id = self.arbitrage_details["exchange_sell_order_id"]
|
|
|
|
|
- msg = f"等待交易所现货卖出订单确认:{exchange_sell_order_id}"
|
|
|
|
|
- logging.info(msg)
|
|
|
|
|
- add_state_flow_entry(self.process_item, self.current_state, msg, "pending")
|
|
|
|
|
- try:
|
|
|
|
|
# 查询交易所订单状态
|
|
# 查询交易所订单状态
|
|
|
waiting_times = 30
|
|
waiting_times = 30
|
|
|
|
|
+ last_query_rst = None
|
|
|
while True:
|
|
while True:
|
|
|
params = {
|
|
params = {
|
|
|
"symbol": self.symbol.replace('_', ''),
|
|
"symbol": self.symbol.replace('_', ''),
|
|
|
- "orderId": exchange_sell_order_id
|
|
|
|
|
|
|
+ "orderId": exchange_buy_order_id
|
|
|
}
|
|
}
|
|
|
order = mexc.trade.get_order(params)
|
|
order = mexc.trade.get_order(params)
|
|
|
|
|
+ last_query_rst = order
|
|
|
|
|
|
|
|
if order['status'] == "FILLED":
|
|
if order['status'] == "FILLED":
|
|
|
- msg = f"交易所现货卖出订单已完全成交。{order}"
|
|
|
|
|
- self.arbitrage_details["exchange_withdraw_amount"] = order['cummulativeQuoteQty']
|
|
|
|
|
|
|
+ money = Decimal(order['cummulativeQuoteQty'])
|
|
|
|
|
+ amount = self.arbitrage_details["exchange_out_amount"]
|
|
|
|
|
+ price = money / amount
|
|
|
|
|
+ price = price.quantize(Decimal('1e-8'), rounding=ROUND_DOWN)
|
|
|
|
|
+
|
|
|
|
|
+ msg = f"【回滚】交易所现货买入订单已完全成交, 价格:{price}。{order}"
|
|
|
|
|
|
|
|
logging.info(msg)
|
|
logging.info(msg)
|
|
|
add_state_flow_entry(self.process_item, self.current_state, msg, "success")
|
|
add_state_flow_entry(self.process_item, self.current_state, msg, "success")
|
|
|
|
|
|
|
|
- self._set_state(self.STATE_WAITING_TRANSFER_ARRIVE)
|
|
|
|
|
|
|
+ self._set_state(self.STATE_FAILED)
|
|
|
return
|
|
return
|
|
|
else:
|
|
else:
|
|
|
# 继续等待成交
|
|
# 继续等待成交
|
|
@@ -343,11 +443,14 @@ class ArbitrageProcess:
|
|
|
|
|
|
|
|
time.sleep(1)
|
|
time.sleep(1)
|
|
|
waiting_times = waiting_times - 1
|
|
waiting_times = waiting_times - 1
|
|
|
|
|
+
|
|
|
|
|
+ msg = f"【回滚】回滚交易订单查询超时, 订单ID: {exchange_buy_order_id},最终状态:{last_query_rst}"
|
|
|
|
|
+ logging.info(msg)
|
|
|
|
|
+ add_state_flow_entry(self.process_item, self.current_state, msg, "fail")
|
|
|
|
|
|
|
|
|
|
+ self._set_state(self.STATE_FAILED)
|
|
|
except Exception as e:
|
|
except Exception as e:
|
|
|
- msg = f"查询交易所现货卖出订单状态时发生错误:{e}"
|
|
|
|
|
- logging.error(msg)
|
|
|
|
|
- add_state_flow_entry(self.process_item, self.current_state, msg, "fail")
|
|
|
|
|
|
|
+ logging.error(f"【回滚】交易所回滚交易失败:{e}")
|
|
|
self._set_state("FAILED")
|
|
self._set_state("FAILED")
|
|
|
|
|
|
|
|
def _wait_transfer_arrive(self):
|
|
def _wait_transfer_arrive(self):
|
|
@@ -555,7 +658,7 @@ if __name__ == "__main__":
|
|
|
SYMBOL, process_item)
|
|
SYMBOL, process_item)
|
|
|
|
|
|
|
|
# 一般都是从这个流程开始,测试时可以稍作修改、测试后续流程
|
|
# 一般都是从这个流程开始,测试时可以稍作修改、测试后续流程
|
|
|
- ap._set_state(ap.STATE_BUYING_ON_CHAIN)
|
|
|
|
|
|
|
+ ap._set_state(ap.SELLING_ON_EXCHANGE)
|
|
|
|
|
|
|
|
# 在主循环中周期性调用 run_arbitrage_step
|
|
# 在主循环中周期性调用 run_arbitrage_step
|
|
|
while ap.current_state != "COMPLETED" and ap.current_state != "FAILED":
|
|
while ap.current_state != "COMPLETED" and ap.current_state != "FAILED":
|
|
@@ -563,8 +666,8 @@ if __name__ == "__main__":
|
|
|
|
|
|
|
|
if ap.current_state == ap.STATE_WAITING_TRANSFER_ARRIVE or ap.current_state == ap.STATE_WAITING_WITHDRAWAL_CONFIRM:
|
|
if ap.current_state == ap.STATE_WAITING_TRANSFER_ARRIVE or ap.current_state == ap.STATE_WAITING_WITHDRAWAL_CONFIRM:
|
|
|
time.sleep(10)
|
|
time.sleep(10)
|
|
|
- else:
|
|
|
|
|
- time.sleep(1)
|
|
|
|
|
|
|
+ # else:
|
|
|
|
|
+ # time.sleep(1)
|
|
|
|
|
|
|
|
logging.info(process_item)
|
|
logging.info(process_item)
|
|
|
if ap.current_state == "COMPLETED":
|
|
if ap.current_state == "COMPLETED":
|