fewfef
This commit is contained in:
@@ -3,12 +3,9 @@ import time
|
||||
import uuid
|
||||
import datetime
|
||||
from dataclasses import dataclass
|
||||
from typing import Optional
|
||||
|
||||
import requests
|
||||
from tqdm import tqdm
|
||||
from loguru import logger
|
||||
from DrissionPage import ChromiumPage, ChromiumOptions
|
||||
|
||||
from bitmart.api_contract import APIContract
|
||||
from bitmart.lib.cloud_exceptions import APIException
|
||||
@@ -27,12 +24,6 @@ class StrategyConfig:
|
||||
open_type: str = "cross"
|
||||
leverage: str = "30"
|
||||
|
||||
# ===== 浏览器配置 =====
|
||||
tge_id: int = 196495 # TGE浏览器ID
|
||||
tge_url: str = "http://127.0.0.1:50326"
|
||||
tge_authorization: str = "Bearer asp_174003986c9b0799677c5b2c1adb76e402735d753bc91a91"
|
||||
trading_url: str = "https://derivatives.bitmart.com/zh-CN/futures/ETHUSDT"
|
||||
|
||||
# ===== K线与指标 =====
|
||||
step_min: int = 1
|
||||
lookback_min: int = 240
|
||||
@@ -158,115 +149,10 @@ class BitmartFuturesMeanReversionBot:
|
||||
self.post_sl_ts = 0.0
|
||||
self.post_sl_vol_scale = 1.0 # 记录止损时的 vol_scale
|
||||
|
||||
# ✅ 浏览器自动化相关
|
||||
self.tge_port: Optional[int] = None
|
||||
self.page: Optional[ChromiumPage] = None
|
||||
self.browser_initialized = False
|
||||
|
||||
self.pbar = tqdm(total=60, desc="运行中(秒)", ncols=90)
|
||||
|
||||
logger.info(f"初始化完成,基准波动率默认值: {self._base_ratio_cached * 100:.4f}%")
|
||||
|
||||
# ----------------- 浏览器自动化相关 -----------------
|
||||
def open_browser(self) -> bool:
|
||||
"""打开 TGE 对应浏览器实例"""
|
||||
try:
|
||||
tge_headers = {
|
||||
"Authorization": self.cfg.tge_authorization,
|
||||
"Content-Type": "application/json"
|
||||
}
|
||||
res = requests.post(
|
||||
f"{self.cfg.tge_url}/api/browser/start",
|
||||
json={"envId": self.cfg.tge_id},
|
||||
headers=tge_headers,
|
||||
timeout=10
|
||||
)
|
||||
self.tge_port = res.json()["data"]["port"]
|
||||
logger.success(f"成功打开浏览器,端口:{self.tge_port}")
|
||||
return True
|
||||
except Exception as e:
|
||||
logger.error(f"打开浏览器失败: {e}")
|
||||
self.ding(f"打开浏览器失败: {e}", error=True)
|
||||
return False
|
||||
|
||||
def take_over_browser(self) -> bool:
|
||||
"""接管浏览器"""
|
||||
if not self.tge_port:
|
||||
logger.error("浏览器端口未设置")
|
||||
return False
|
||||
|
||||
try:
|
||||
co = ChromiumOptions()
|
||||
co.set_local_port(self.tge_port)
|
||||
self.page = ChromiumPage(addr_or_opts=co)
|
||||
self.page.set.window.max()
|
||||
logger.success("成功接管浏览器")
|
||||
return True
|
||||
except Exception as e:
|
||||
logger.error(f"接管浏览器失败: {e}")
|
||||
self.ding(f"接管浏览器失败: {e}", error=True)
|
||||
return False
|
||||
|
||||
def close_extra_tabs(self) -> bool:
|
||||
"""关闭多余 tab"""
|
||||
if not self.page:
|
||||
return False
|
||||
|
||||
try:
|
||||
for idx, tab in enumerate(self.page.get_tabs()):
|
||||
if idx > 0:
|
||||
tab.close()
|
||||
return True
|
||||
except Exception as e:
|
||||
logger.warning(f"关闭多余标签页失败: {e}")
|
||||
return False
|
||||
|
||||
def initialize_browser(self) -> bool:
|
||||
"""初始化浏览器(打开、接管、导航到交易页面)"""
|
||||
if self.browser_initialized:
|
||||
return True
|
||||
|
||||
# 打开浏览器
|
||||
if not self.open_browser():
|
||||
return False
|
||||
|
||||
# 接管浏览器
|
||||
if not self.take_over_browser():
|
||||
return False
|
||||
|
||||
# 关闭多余标签页
|
||||
self.close_extra_tabs()
|
||||
|
||||
# 导航到交易页面
|
||||
try:
|
||||
self.page.get(self.cfg.trading_url)
|
||||
time.sleep(2) # 等待页面加载
|
||||
logger.success("已导航到交易页面")
|
||||
except Exception as e:
|
||||
logger.error(f"导航到交易页面失败: {e}")
|
||||
self.ding(f"导航到交易页面失败: {e}", error=True)
|
||||
return False
|
||||
|
||||
self.browser_initialized = True
|
||||
return True
|
||||
|
||||
def click_safe(self, xpath: str, sleep: float = 0.5) -> bool:
|
||||
"""安全点击"""
|
||||
if not self.page:
|
||||
return False
|
||||
|
||||
try:
|
||||
ele = self.page.ele(xpath)
|
||||
if not ele:
|
||||
return False
|
||||
ele.scroll.to_see(center=True)
|
||||
time.sleep(sleep)
|
||||
ele.click()
|
||||
return True
|
||||
except Exception as e:
|
||||
logger.error(f"点击失败 {xpath}: {e}")
|
||||
return False
|
||||
|
||||
# ----------------- 通用工具 -----------------
|
||||
def ding(self, msg, error=False):
|
||||
prefix = "❌bitmart:" if error else "🔔bitmart:"
|
||||
@@ -638,7 +524,7 @@ class BitmartFuturesMeanReversionBot:
|
||||
self.trading_enabled = False
|
||||
self.ding(f"达到日盈利封顶:{pnl * 100:.2f}% -> 停机")
|
||||
|
||||
# ----------------- 下单(使用浏览器自动化) -----------------
|
||||
# ----------------- 下单 -----------------
|
||||
def calculate_size(self, price: float) -> int:
|
||||
bal = self.get_assets_available()
|
||||
if bal < 10:
|
||||
@@ -654,116 +540,6 @@ class BitmartFuturesMeanReversionBot:
|
||||
return size
|
||||
|
||||
def place_market_order(self, side: int, size: int) -> bool:
|
||||
"""
|
||||
使用浏览器自动化开单(市价单)
|
||||
|
||||
Args:
|
||||
side: 1=开多, 4=开空
|
||||
size: 数量(张数)
|
||||
|
||||
Returns:
|
||||
是否成功
|
||||
"""
|
||||
if size <= 0:
|
||||
return False
|
||||
|
||||
# 确保浏览器已初始化
|
||||
if not self.browser_initialized:
|
||||
if not self.initialize_browser():
|
||||
logger.error("浏览器初始化失败,无法开单")
|
||||
self.ding("浏览器初始化失败,无法开单", error=True)
|
||||
return False
|
||||
|
||||
try:
|
||||
# 刷新页面确保在交易页面
|
||||
if self.page:
|
||||
self.page.get(self.cfg.trading_url)
|
||||
time.sleep(1)
|
||||
|
||||
# 根据side判断方向
|
||||
if side == 1:
|
||||
# 开多:点击市价,输入数量,点击买入/做多
|
||||
if not self.click_safe('x://button[normalize-space(text()) ="市价"]'):
|
||||
logger.error("点击市价按钮失败")
|
||||
return False
|
||||
|
||||
# 输入数量
|
||||
try:
|
||||
size_input = self.page.ele('x://*[@id="size_0"]')
|
||||
if size_input:
|
||||
size_input.input(str(size))
|
||||
time.sleep(0.5)
|
||||
else:
|
||||
logger.error("找不到数量输入框")
|
||||
return False
|
||||
except Exception as e:
|
||||
logger.error(f"输入数量失败: {e}")
|
||||
return False
|
||||
|
||||
# 点击买入/做多
|
||||
if not self.click_safe('x://span[normalize-space(text()) ="买入/做多"]'):
|
||||
logger.error("点击买入/做多按钮失败")
|
||||
return False
|
||||
|
||||
logger.success(f"浏览器自动化开多成功: size={size}")
|
||||
return True
|
||||
|
||||
elif side == 4:
|
||||
# 开空:点击市价,输入数量,点击卖出/做空
|
||||
if not self.click_safe('x://button[normalize-space(text()) ="市价"]'):
|
||||
logger.error("点击市价按钮失败")
|
||||
return False
|
||||
|
||||
# 输入数量
|
||||
try:
|
||||
size_input = self.page.ele('x://*[@id="size_0"]')
|
||||
if size_input:
|
||||
size_input.input(str(size))
|
||||
time.sleep(0.5)
|
||||
else:
|
||||
logger.error("找不到数量输入框")
|
||||
return False
|
||||
except Exception as e:
|
||||
logger.error(f"输入数量失败: {e}")
|
||||
return False
|
||||
|
||||
# 点击卖出/做空
|
||||
if not self.click_safe('x://span[normalize-space(text()) ="卖出/做空"]'):
|
||||
logger.error("点击卖出/做空按钮失败")
|
||||
return False
|
||||
|
||||
logger.success(f"浏览器自动化开空成功: size={size}")
|
||||
return True
|
||||
else:
|
||||
logger.error(f"不支持的side参数: {side} (只支持1=开多, 4=开空)")
|
||||
return False
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"浏览器自动化开单异常: {e}")
|
||||
self.ding(f"浏览器自动化开单异常: {e}", error=True)
|
||||
return False
|
||||
|
||||
def close_position_all(self):
|
||||
"""
|
||||
使用API平仓(保持原有逻辑)
|
||||
"""
|
||||
if self.pos == 1:
|
||||
ok = self.place_market_order_api(3, 999999)
|
||||
if ok:
|
||||
self.pos = 0
|
||||
elif self.pos == -1:
|
||||
ok = self.place_market_order_api(2, 999999)
|
||||
if ok:
|
||||
self.pos = 0
|
||||
|
||||
def place_market_order_api(self, side: int, size: int) -> bool:
|
||||
"""
|
||||
使用API下单(仅用于平仓)
|
||||
|
||||
Args:
|
||||
side: 2=平空, 3=平多
|
||||
size: 数量
|
||||
"""
|
||||
if size <= 0:
|
||||
return False
|
||||
|
||||
@@ -780,24 +556,34 @@ class BitmartFuturesMeanReversionBot:
|
||||
size=size
|
||||
)[0]
|
||||
|
||||
logger.info(f"API平仓响应: {resp}")
|
||||
logger.info(f"order_resp: {resp}")
|
||||
|
||||
if resp.get("code") == 1000:
|
||||
return True
|
||||
|
||||
self.ding(f"API平仓失败: {resp}", error=True)
|
||||
self.ding(f"下单失败: {resp}", error=True)
|
||||
return False
|
||||
|
||||
except APIException as e:
|
||||
logger.error(f"API平仓异常: {e}")
|
||||
self.ding(f"API平仓异常: {e}", error=True)
|
||||
logger.error(f"API下单异常: {e}")
|
||||
self.ding(f"API下单异常: {e}", error=True)
|
||||
return False
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"API平仓未知异常: {e}")
|
||||
self.ding(f"API平仓未知异常: {e}", error=True)
|
||||
logger.error(f"下单未知异常: {e}")
|
||||
self.ding(f"下单未知异常: {e}", error=True)
|
||||
return False
|
||||
|
||||
def close_position_all(self):
|
||||
if self.pos == 1:
|
||||
ok = self.place_market_order(3, 999999)
|
||||
if ok:
|
||||
self.pos = 0
|
||||
elif self.pos == -1:
|
||||
ok = self.place_market_order(2, 999999)
|
||||
if ok:
|
||||
self.pos = 0
|
||||
|
||||
# ----------------- 止损后机制 -----------------
|
||||
def _reentry_penalty_active(self, dev: float, entry_dev: float) -> bool:
|
||||
"""检查是否需要应用重新入场惩罚"""
|
||||
@@ -970,13 +756,6 @@ class BitmartFuturesMeanReversionBot:
|
||||
self.ding("杠杆设置失败,停止运行", error=True)
|
||||
return
|
||||
|
||||
# 初始化浏览器(延迟初始化,在需要开单时再初始化)
|
||||
# 这里可以选择提前初始化,或者在place_market_order中初始化
|
||||
# 为了更好的用户体验,可以选择在这里提前初始化
|
||||
logger.info("准备初始化浏览器...")
|
||||
if not self.initialize_browser():
|
||||
logger.warning("浏览器初始化失败,将在首次开单时重试")
|
||||
|
||||
while True:
|
||||
now_dt = datetime.datetime.now()
|
||||
self.pbar.n = now_dt.second
|
||||
@@ -1084,3 +863,4 @@ if __name__ == "__main__":
|
||||
bot.ding(f"❌ 策略异常退出: {e}", error=True)
|
||||
raise
|
||||
|
||||
# 目前动态计算阀值的速度是多少
|
||||
@@ -204,7 +204,7 @@ class BitmartFuturesTransaction:
|
||||
|
||||
def 开单(self, marketPriceLongOrder=0, limitPriceShortOrder=0, size=None, price=None):
|
||||
"""
|
||||
marketPriceLongOrder 市价最多或者做空,1是最多,-1是做空
|
||||
marketPriceLongOrder 市价最多或者做空,1是做多,-1是做空
|
||||
limitPriceShortOrder 限价最多或者做空
|
||||
"""
|
||||
|
||||
|
||||
10
推特/main.py
10
推特/main.py
@@ -585,10 +585,10 @@ Win–win benefits — don’t miss out! 🚀
|
||||
def 回复(self):
|
||||
|
||||
urls = [
|
||||
"https://x.com/Websea_MY/status/1999305458566463782",
|
||||
"https://x.com/Websea_MY/status/2000021069311402186",
|
||||
"https://x.com/Websea_MY/status/2001119115575222779",
|
||||
"https://x.com/Websea_MY/status/2001180999443734677"
|
||||
"https://x.com/Websea_MY/status/2003700808186278388",
|
||||
"https://x.com/Websea_MY/status/2003669526492405904",
|
||||
# "https://x.com/Websea_MY/status/2001119115575222779",
|
||||
# "https://x.com/Websea_MY/status/2001180999443734677"
|
||||
]
|
||||
tests = [
|
||||
"Canal premium de Websea: Regístrese para disfrutar de descuentos del 85 % en las comisiones de los futuros de Websea. Para grandes volúmenes de registros, el porcentaje es negociable. Agentes bienvenidos a consultar. Contacto Telegram: @webseatom",
|
||||
@@ -739,7 +739,7 @@ def run_work(x_token_info, xstart_info):
|
||||
pass
|
||||
|
||||
# hub.to_do_tui() # 发推
|
||||
# hub.回复() # 发推
|
||||
hub.回复() # 发推
|
||||
|
||||
# hub.FollowTwitterAccount() # 关注
|
||||
|
||||
|
||||
Reference in New Issue
Block a user