哈哈
This commit is contained in:
@@ -65,6 +65,14 @@ class BitmartFuturesTransaction:
|
|||||||
self.prev_entity = None # 上一根K线实体大小
|
self.prev_entity = None # 上一根K线实体大小
|
||||||
self.current_open = None # 当前K线开盘价
|
self.current_open = None # 当前K线开盘价
|
||||||
|
|
||||||
|
# API 节流:主循环与持仓/价格查询间隔,避免 429 Request too many requests
|
||||||
|
self.loop_interval_seconds = 2.5 # 每轮循环最少间隔(秒)
|
||||||
|
self._last_position_fetch = 0.0
|
||||||
|
self._last_price_fetch = 0.0
|
||||||
|
self._position_refresh_interval = 2.0 # 持仓/价格最少隔多久才重新请求(秒)
|
||||||
|
self._position_cache = None # 上次成功的持仓状态,用于节流时复用
|
||||||
|
self._price_cache = None # 上次成功的价格,用于节流时复用
|
||||||
|
|
||||||
def get_klines(self):
|
def get_klines(self):
|
||||||
"""获取最近2根K线(当前K线和上一根K线)"""
|
"""获取最近2根K线(当前K线和上一根K线)"""
|
||||||
try:
|
try:
|
||||||
@@ -99,9 +107,12 @@ class BitmartFuturesTransaction:
|
|||||||
return None, None
|
return None, None
|
||||||
|
|
||||||
def get_current_price(self):
|
def get_current_price(self):
|
||||||
"""获取当前最新价格"""
|
"""获取当前最新价格(带节流:间隔内返回缓存值)"""
|
||||||
|
now = time.time()
|
||||||
|
if self._price_cache is not None and (now - self._last_price_fetch) < self._position_refresh_interval:
|
||||||
|
return self._price_cache
|
||||||
try:
|
try:
|
||||||
end_time = int(time.time())
|
end_time = int(now)
|
||||||
response = self.contractAPI.get_kline(
|
response = self.contractAPI.get_kline(
|
||||||
contract_symbol=self.contract_symbol,
|
contract_symbol=self.contract_symbol,
|
||||||
step=1, # 1分钟
|
step=1, # 1分钟
|
||||||
@@ -109,11 +120,14 @@ class BitmartFuturesTransaction:
|
|||||||
end_time=end_time
|
end_time=end_time
|
||||||
)[0]
|
)[0]
|
||||||
if response['code'] == 1000:
|
if response['code'] == 1000:
|
||||||
return float(response['data'][-1]["close_price"])
|
price = float(response['data'][-1]["close_price"])
|
||||||
return None
|
self._price_cache = price
|
||||||
|
self._last_price_fetch = now
|
||||||
|
return price
|
||||||
|
return self._price_cache # 失败时用旧价格
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"获取价格异常: {e}")
|
logger.error(f"获取价格异常: {e}")
|
||||||
return None
|
return self._price_cache
|
||||||
|
|
||||||
def get_available_balance(self):
|
def get_available_balance(self):
|
||||||
"""获取合约账户可用USDT余额"""
|
"""获取合约账户可用USDT余额"""
|
||||||
@@ -133,7 +147,15 @@ class BitmartFuturesTransaction:
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
def get_position_status(self):
|
def get_position_status(self):
|
||||||
"""获取当前持仓方向"""
|
"""获取当前持仓方向(带节流:间隔内返回缓存状态)"""
|
||||||
|
now = time.time()
|
||||||
|
if self._position_cache is not None and (now - self._last_position_fetch) < self._position_refresh_interval:
|
||||||
|
c = self._position_cache
|
||||||
|
self.start = c['start']
|
||||||
|
self.open_avg_price = c.get('open_avg_price')
|
||||||
|
self.current_amount = c.get('current_amount')
|
||||||
|
self.unrealized_pnl = c.get('unrealized_pnl')
|
||||||
|
return True
|
||||||
try:
|
try:
|
||||||
response = self.contractAPI.get_position(contract_symbol=self.contract_symbol)[0]
|
response = self.contractAPI.get_position(contract_symbol=self.contract_symbol)[0]
|
||||||
if response['code'] == 1000:
|
if response['code'] == 1000:
|
||||||
@@ -143,21 +165,34 @@ class BitmartFuturesTransaction:
|
|||||||
self.open_avg_price = None
|
self.open_avg_price = None
|
||||||
self.current_amount = None
|
self.current_amount = None
|
||||||
self.unrealized_pnl = None
|
self.unrealized_pnl = None
|
||||||
|
self._position_cache = {'start': 0, 'open_avg_price': None, 'current_amount': None, 'unrealized_pnl': None}
|
||||||
|
self._last_position_fetch = now
|
||||||
return True
|
return True
|
||||||
pos = positions[0]
|
pos = positions[0]
|
||||||
self.start = 1 if pos['position_type'] == 1 else -1
|
self.start = 1 if pos['position_type'] == 1 else -1
|
||||||
self.open_avg_price = float(pos['open_avg_price'])
|
self.open_avg_price = float(pos['open_avg_price'])
|
||||||
self.current_amount = float(pos['current_amount'])
|
self.current_amount = float(pos['current_amount'])
|
||||||
self.position_cross = pos["position_cross"]
|
self.position_cross = pos["position_cross"]
|
||||||
# 直接从API获取未实现盈亏(Bitmart返回的是 unrealized_value 字段)
|
|
||||||
self.unrealized_pnl = float(pos.get('unrealized_value', 0))
|
self.unrealized_pnl = float(pos.get('unrealized_value', 0))
|
||||||
|
self._position_cache = {'start': self.start, 'open_avg_price': self.open_avg_price, 'current_amount': self.current_amount, 'unrealized_pnl': self.unrealized_pnl}
|
||||||
|
self._last_position_fetch = now
|
||||||
logger.debug(f"持仓详情: 方向={self.start}, 开仓均价={self.open_avg_price}, "
|
logger.debug(f"持仓详情: 方向={self.start}, 开仓均价={self.open_avg_price}, "
|
||||||
f"持仓量={self.current_amount}, 未实现盈亏={self.unrealized_pnl:.2f}")
|
f"持仓量={self.current_amount}, 未实现盈亏={self.unrealized_pnl:.2f}")
|
||||||
return True
|
return True
|
||||||
else:
|
else:
|
||||||
|
if self._position_cache is not None:
|
||||||
|
c = self._position_cache
|
||||||
|
self.start, self.open_avg_price = c['start'], c.get('open_avg_price')
|
||||||
|
self.current_amount, self.unrealized_pnl = c.get('current_amount'), c.get('unrealized_pnl')
|
||||||
|
return True # 请求失败但用缓存
|
||||||
return False
|
return False
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"持仓查询异常: {e}")
|
logger.error(f"持仓查询异常: {e}")
|
||||||
|
if self._position_cache is not None:
|
||||||
|
c = self._position_cache
|
||||||
|
self.start, self.open_avg_price = c['start'], c.get('open_avg_price')
|
||||||
|
self.current_amount, self.unrealized_pnl = c.get('current_amount'), c.get('unrealized_pnl')
|
||||||
|
return True # 429 等异常时用缓存
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def get_unrealized_pnl_usd(self):
|
def get_unrealized_pnl_usd(self):
|
||||||
@@ -492,6 +527,7 @@ class BitmartFuturesTransaction:
|
|||||||
self.max_unrealized_pnl_seen = None # 新仓位重置移动止损记录
|
self.max_unrealized_pnl_seen = None # 新仓位重置移动止损记录
|
||||||
self.last_open_time = time.time()
|
self.last_open_time = time.time()
|
||||||
self.last_open_kline_id = getattr(self, "_current_kline_id_for_open", None)
|
self.last_open_kline_id = getattr(self, "_current_kline_id_for_open", None)
|
||||||
|
self._last_position_fetch = 0 # 强制下一轮重新拉持仓
|
||||||
logger.success("开多成功")
|
logger.success("开多成功")
|
||||||
return True
|
return True
|
||||||
else:
|
else:
|
||||||
@@ -517,6 +553,7 @@ class BitmartFuturesTransaction:
|
|||||||
self.max_unrealized_pnl_seen = None # 新仓位重置移动止损记录
|
self.max_unrealized_pnl_seen = None # 新仓位重置移动止损记录
|
||||||
self.last_open_time = time.time()
|
self.last_open_time = time.time()
|
||||||
self.last_open_kline_id = getattr(self, "_current_kline_id_for_open", None)
|
self.last_open_kline_id = getattr(self, "_current_kline_id_for_open", None)
|
||||||
|
self._last_position_fetch = 0 # 强制下一轮重新拉持仓
|
||||||
logger.success("开空成功")
|
logger.success("开空成功")
|
||||||
return True
|
return True
|
||||||
else:
|
else:
|
||||||
@@ -542,6 +579,7 @@ class BitmartFuturesTransaction:
|
|||||||
|
|
||||||
if self.verify_position_direction(1):
|
if self.verify_position_direction(1):
|
||||||
self.max_unrealized_pnl_seen = None
|
self.max_unrealized_pnl_seen = None
|
||||||
|
self._last_position_fetch = 0 # 强制下一轮重新拉持仓
|
||||||
logger.success("反手做多成功")
|
logger.success("反手做多成功")
|
||||||
self.last_reverse_time = time.time()
|
self.last_reverse_time = time.time()
|
||||||
time.sleep(20)
|
time.sleep(20)
|
||||||
@@ -568,6 +606,7 @@ class BitmartFuturesTransaction:
|
|||||||
|
|
||||||
if self.verify_position_direction(-1):
|
if self.verify_position_direction(-1):
|
||||||
self.max_unrealized_pnl_seen = None
|
self.max_unrealized_pnl_seen = None
|
||||||
|
self._last_position_fetch = 0 # 强制下一轮重新拉持仓
|
||||||
logger.success("反手做空成功")
|
logger.success("反手做空成功")
|
||||||
self.last_reverse_time = time.time()
|
self.last_reverse_time = time.time()
|
||||||
time.sleep(20)
|
time.sleep(20)
|
||||||
@@ -698,8 +737,8 @@ class BitmartFuturesTransaction:
|
|||||||
else:
|
else:
|
||||||
logger.warning(f"交易执行失败或被阻止: {signal[0]}")
|
logger.warning(f"交易执行失败或被阻止: {signal[0]}")
|
||||||
|
|
||||||
# 短暂等待后继续循环(同一根K线遇到信号就操作)
|
# 主循环间隔,避免持仓/价格查询过于频繁触发 429
|
||||||
time.sleep(0.1)
|
time.sleep(self.loop_interval_seconds)
|
||||||
|
|
||||||
if page_start:
|
if page_start:
|
||||||
self.page.close()
|
self.page.close()
|
||||||
|
|||||||
Reference in New Issue
Block a user