bitmart优化完成
This commit is contained in:
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -120,10 +120,12 @@ class WeexTransaction:
|
||||
for _ in range(3):
|
||||
try:
|
||||
tab.get("https://derivatives.bitmart.com/zh-CN/futures/ETHUSDT")
|
||||
res = tab.listen.wait(timeout=5)
|
||||
res = tab.listen.wait(timeout=15)
|
||||
|
||||
# 请求头 + Cookies
|
||||
self.session.headers.update(res.request.headers)
|
||||
for i in res.request.headers:
|
||||
if ":" not in i:
|
||||
self.session.headers[i] = res.request.headers[i]
|
||||
|
||||
for c in res.request.cookies:
|
||||
self.cookies[c["name"]] = c["value"]
|
||||
@@ -309,93 +311,89 @@ class WeexTransaction:
|
||||
|
||||
self.pbar = tqdm(total=30, desc="等待半小时周期", ncols=80)
|
||||
|
||||
now = time.localtime()
|
||||
minute = now.tm_min
|
||||
while True:
|
||||
now = time.localtime()
|
||||
minute = now.tm_min
|
||||
|
||||
# 更新进度条
|
||||
self.pbar.n = minute if minute < 30 else minute - 30
|
||||
self.pbar.refresh()
|
||||
# 更新进度条
|
||||
self.pbar.n = minute if minute < 30 else minute - 30
|
||||
self.pbar.refresh()
|
||||
|
||||
# 必须是整点或半点及前 5 分钟
|
||||
if minute not in [0, 1, 2, 3, 4, 5, 30, 31, 32, 33, 34, 35]:
|
||||
time.sleep(8)
|
||||
return
|
||||
# # 必须是整点或半点及前 5 分钟
|
||||
# if minute not in [0, 1, 2, 3, 4, 5, 30, 31, 32, 33, 34, 35]:
|
||||
# time.sleep(8)
|
||||
# return
|
||||
|
||||
# 时间重复跳过
|
||||
if self.time_start == self.get_half_hour_timestamp():
|
||||
time.sleep(5)
|
||||
return
|
||||
|
||||
# ---- 获取 Token ----
|
||||
if not self.get_token():
|
||||
self.ding("获取 token 失败!", error=True)
|
||||
return
|
||||
logger.info("Token 获取成功")
|
||||
|
||||
# ---- 获取价格 ----
|
||||
kdatas = self.get_price()
|
||||
if not kdatas:
|
||||
self.ding("获取价格失败!", error=True)
|
||||
return
|
||||
|
||||
self.kline_1, self.kline_2, self.kline_3 = kdatas[-3:]
|
||||
if int(self.kline_3["id"]) != self.get_half_hour_timestamp():
|
||||
return
|
||||
|
||||
logger.success("K线获取成功")
|
||||
|
||||
self.time_start = self.get_half_hour_timestamp()
|
||||
|
||||
# ---- 刷新页面 ----
|
||||
self.page.get("https://derivatives.bitmart.com/zh-CN/futures/ETHUSDT")
|
||||
|
||||
for i in range(3):
|
||||
# ---- 获取仓位 ----
|
||||
if not self.get_position_status():
|
||||
self.ding("获取仓位失败!", error=True)
|
||||
# 时间重复跳过
|
||||
if self.time_start == self.get_half_hour_timestamp():
|
||||
time.sleep(5)
|
||||
continue
|
||||
|
||||
if self.start:
|
||||
break
|
||||
# ---- 获取 Token ----
|
||||
if not self.get_token():
|
||||
self.ding("获取 token 失败!", error=True)
|
||||
return
|
||||
logger.info("Token 获取成功")
|
||||
|
||||
# ---- 止损平仓 ----
|
||||
try:
|
||||
if self.start == 1 and is_bearish(self.kline_1) and is_bearish(self.kline_2):
|
||||
self.ding("两根大阴线,平多")
|
||||
self.click_safe('x://span[normalize-space(text()) ="市价"]')
|
||||
self.start = 0
|
||||
# ---- 获取价格 ----
|
||||
kdatas = self.get_price()
|
||||
if not kdatas:
|
||||
self.ding("获取价格失败!", error=True)
|
||||
return
|
||||
|
||||
elif self.start == -1 and is_bullish(self.kline_1) and is_bullish(self.kline_2):
|
||||
self.ding("两根大阳线,平空")
|
||||
self.click_safe('x://span[normalize-space(text()) ="市价"]')
|
||||
self.start = 0
|
||||
except:
|
||||
self.ding("止损平仓错误!", error=True)
|
||||
# continue
|
||||
return
|
||||
self.kline_1, self.kline_2, self.kline_3 = kdatas[-3:]
|
||||
if int(self.kline_3["id"]) != self.get_half_hour_timestamp():
|
||||
continue
|
||||
|
||||
# ---- 生成新信号 ----
|
||||
self.direction = self.check_signal(prev=self.kline_1, curr=self.kline_2)
|
||||
logger.success("K线获取成功")
|
||||
|
||||
# ---- 执行交易 ----
|
||||
if self.direction:
|
||||
self.time_start = self.get_half_hour_timestamp()
|
||||
|
||||
# ---- 刷新页面 ----
|
||||
self.page.get("https://derivatives.bitmart.com/zh-CN/futures/ETHUSDT")
|
||||
|
||||
for i in range(3):
|
||||
# ---- 获取仓位 ----
|
||||
if not self.get_position_status():
|
||||
self.ding("获取仓位失败!", error=True)
|
||||
continue
|
||||
|
||||
if self.start:
|
||||
break
|
||||
|
||||
# ---- 止损平仓 ----
|
||||
try:
|
||||
self.do_order()
|
||||
except:
|
||||
self.ding("下单失败!", error=True)
|
||||
if self.start == 1 and is_bearish(self.kline_1) and is_bearish(self.kline_2):
|
||||
self.ding("两根大阴线,平多")
|
||||
self.click_safe('x://span[normalize-space(text()) ="市价"]')
|
||||
self.start = 0
|
||||
|
||||
# ---- 周期结束消息 ----
|
||||
self.pbar.reset()
|
||||
self.ding(
|
||||
f"持仓:{'无' if self.start == 0 else ('多' if self.start == 1 else '空')},"
|
||||
f"信号:{'无' if not self.direction else ('多' if self.direction == 'long' else '空')}"
|
||||
)
|
||||
elif self.start == -1 and is_bullish(self.kline_1) and is_bullish(self.kline_2):
|
||||
self.ding("两根大阳线,平空")
|
||||
self.click_safe('x://span[normalize-space(text()) ="市价"]')
|
||||
self.start = 0
|
||||
except:
|
||||
self.ding("止损平仓错误!", error=True)
|
||||
# continue
|
||||
return
|
||||
|
||||
# ---- 生成新信号 ----
|
||||
self.direction = self.check_signal(prev=self.kline_1, curr=self.kline_2)
|
||||
|
||||
# ---- 执行交易 ----
|
||||
if self.direction:
|
||||
try:
|
||||
self.do_order()
|
||||
except:
|
||||
self.ding("下单失败!", error=True)
|
||||
|
||||
# ---- 周期结束消息 ----
|
||||
self.pbar.reset()
|
||||
self.ding(
|
||||
f"持仓:{'无' if self.start == 0 else ('多' if self.start == 1 else '空')},"
|
||||
f"信号:{'无' if not self.direction else ('多' if self.direction == 'long' else '空')}"
|
||||
)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
while True:
|
||||
try:
|
||||
WeexTransaction(tge_id=196495).action()
|
||||
except:
|
||||
pass
|
||||
time.sleep(30)
|
||||
WeexTransaction(tge_id=196495).action()
|
||||
|
||||
@@ -353,17 +353,18 @@ class WeexTransaction:
|
||||
self.pbar.refresh()
|
||||
|
||||
if current_minute not in [0, 1, 2, 3, 4, 5, 30, 31, 32, 33, 34, 35]: # 判断是否是 新的30分钟了
|
||||
# if current_minute not in range(60): # 判断是否是 新的30分钟了
|
||||
# if current_minute not in range(60): # 判断是否是 新的30分钟了
|
||||
time.sleep(10)
|
||||
continue
|
||||
|
||||
if not self.kline_3 or self.get_now_time() != self.kline_3["id"]:
|
||||
if self.get_token(): # 获取token
|
||||
logger.info("获取token成功!!!")
|
||||
else:
|
||||
logger.info("获取token失败!!!")
|
||||
self.send_dingtalk_message(message_content=f"获取token失败!!!", type=0)
|
||||
continue
|
||||
if self.kline_3 and self.get_now_time() == self.kline_3["id"]:
|
||||
continue
|
||||
|
||||
if self.get_token(): # 获取token
|
||||
logger.info("获取token成功!!!")
|
||||
else:
|
||||
logger.info("获取token失败!!!")
|
||||
self.send_dingtalk_message(message_content=f"获取token失败!!!", type=0)
|
||||
|
||||
new_price_datas = self.get_price()
|
||||
if not new_price_datas:
|
||||
|
||||
357
交易/weex_优化版.py
357
交易/weex_优化版.py
@@ -1,357 +0,0 @@
|
||||
import time
|
||||
import datetime
|
||||
import asyncio
|
||||
from tqdm import tqdm
|
||||
from loguru import logger
|
||||
from DrissionPage import ChromiumOptions, ChromiumPage
|
||||
from curl_cffi import requests
|
||||
|
||||
from 交易.tools import send_dingtalk_message
|
||||
|
||||
|
||||
# ----------------------------------------------
|
||||
# 工具函数
|
||||
# ----------------------------------------------
|
||||
def is_bullish(candle): # 阳线
|
||||
return float(candle["close"]) > float(candle["open"])
|
||||
|
||||
|
||||
def is_bearish(candle): # 阴线
|
||||
return float(candle["close"]) < float(candle["open"])
|
||||
|
||||
|
||||
def now_str():
|
||||
return datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
||||
|
||||
|
||||
# ----------------------------------------------
|
||||
# 主类
|
||||
# ----------------------------------------------
|
||||
class WeexTransaction:
|
||||
def __init__(self, tge_id):
|
||||
# ===================== 基础配置 =====================
|
||||
self.tge_id = tge_id
|
||||
self.tge_port = None
|
||||
self.tge_url = "http://127.0.0.1:50326"
|
||||
|
||||
self.tge_headers = {
|
||||
"Authorization": "Bearer asp_174003986c9b0799677c5b2c1adb76e402735d753bc91a91",
|
||||
"Content-Type": "application/json"
|
||||
}
|
||||
|
||||
# 浏览器
|
||||
self.page: ChromiumPage = None
|
||||
|
||||
# 当前仓位状态 -1空仓,0无仓位,1多仓
|
||||
self.start = 0
|
||||
|
||||
# 保存 k 线
|
||||
self.kline_1 = None
|
||||
self.kline_2 = None
|
||||
self.kline_3 = None
|
||||
|
||||
# 当前信号方向
|
||||
self.direction = None
|
||||
|
||||
# 进度条
|
||||
self.pbar = None
|
||||
|
||||
# HTTP session
|
||||
self.session = requests.Session()
|
||||
self.session.headers = {}
|
||||
|
||||
# 避免同一分钟重复触发
|
||||
self.last_action_time = None
|
||||
|
||||
# -------------------------------------------------------
|
||||
# DingTalk 通知
|
||||
# -------------------------------------------------------
|
||||
def send_msg(self, msg, err=False):
|
||||
prefix = "❌" if err else "🔔"
|
||||
send_dingtalk_message(f"{prefix}weex:{now_str()},{msg}")
|
||||
|
||||
# -------------------------------------------------------
|
||||
# BitBrowser 控制
|
||||
# -------------------------------------------------------
|
||||
def open_browser(self):
|
||||
try:
|
||||
resp = requests.post(
|
||||
f"{self.tge_url}/api/browser/start",
|
||||
json={"envId": self.tge_id},
|
||||
headers=self.tge_headers
|
||||
)
|
||||
|
||||
self.tge_port = resp.json()["data"]["port"]
|
||||
return True
|
||||
except Exception as e:
|
||||
logger.error(f"打开 TGE 浏览器失败:{e}")
|
||||
return False
|
||||
|
||||
def takeover_browser(self):
|
||||
try:
|
||||
co = ChromiumOptions()
|
||||
co.set_local_port(self.tge_port)
|
||||
|
||||
self.page = ChromiumPage(addr_or_opts=co)
|
||||
self.page.set.window.max()
|
||||
return True
|
||||
except Exception as e:
|
||||
logger.error(f"接管浏览器失败:{e}")
|
||||
return False
|
||||
|
||||
# -------------------------------------------------------
|
||||
# 数据接口
|
||||
# -------------------------------------------------------
|
||||
def get_price(self):
|
||||
params = {
|
||||
'unit': '30',
|
||||
'resolution': 'M',
|
||||
'contractID': '2',
|
||||
'offset': '340',
|
||||
'endTime': str(int(time.time())),
|
||||
}
|
||||
|
||||
for _ in range(3):
|
||||
try:
|
||||
resp = self.session.get(
|
||||
'https://contract-v2.bitmart.com/v1/ifcontract/quote/kline',
|
||||
params=params,
|
||||
timeout=5
|
||||
)
|
||||
result = []
|
||||
for i in resp.json()["data"]:
|
||||
result.append({
|
||||
'id': int(i["timestamp"]) - 1,
|
||||
'open': float(i["open"]),
|
||||
'high': float(i["high"]),
|
||||
'low': float(i["low"]),
|
||||
'close': float(i["close"]),
|
||||
})
|
||||
return sorted(result, key=lambda x: x["id"])
|
||||
except:
|
||||
time.sleep(1)
|
||||
|
||||
return None
|
||||
|
||||
# -------------------------------------------------------
|
||||
# Token 获取
|
||||
# -------------------------------------------------------
|
||||
def get_token(self):
|
||||
tab = self.page.new_tab()
|
||||
tab.listen.start("/user/security/getLanguageType")
|
||||
|
||||
for _ in range(3):
|
||||
try:
|
||||
tab.get("https://www.weeaxs.site/zh-CN/futures/ETH-USDT")
|
||||
res = tab.listen.wait(timeout=5)
|
||||
|
||||
token = res.request.headers.get("U-TOKEN")
|
||||
if token:
|
||||
self.session.headers["U-TOKEN"] = token
|
||||
tab.close()
|
||||
return True
|
||||
except:
|
||||
time.sleep(1)
|
||||
|
||||
tab.close()
|
||||
return False
|
||||
|
||||
# -------------------------------------------------------
|
||||
# 获取账户余额
|
||||
# -------------------------------------------------------
|
||||
def get_balance(self):
|
||||
for _ in range(3):
|
||||
try:
|
||||
resp = self.session.post(
|
||||
"https://gateway2.ngsvsfx.cn/v1/gw/assetsWithBalance/new"
|
||||
)
|
||||
return resp.json()["data"]["newContract"]["balanceList"][0]["accountRights"]
|
||||
except:
|
||||
time.sleep(1)
|
||||
return None
|
||||
|
||||
# -------------------------------------------------------
|
||||
# 查询仓位状态
|
||||
# -------------------------------------------------------
|
||||
def get_position(self):
|
||||
payload = {
|
||||
'filterContractIdList': [10000002],
|
||||
'limit': 100,
|
||||
'languageType': 0,
|
||||
'sign': 'SIGN',
|
||||
'timeZone': 'string',
|
||||
}
|
||||
|
||||
for _ in range(3):
|
||||
try:
|
||||
resp = self.session.post(
|
||||
"https://http-gateway2.ngsvsfx.cn/api/v1/private/order/v2/getHistoryOrderFillTransactionPage",
|
||||
json=payload,
|
||||
)
|
||||
lst = resp.json()["data"]["dataList"]
|
||||
last = lst[0]["legacyOrderDirection"]
|
||||
|
||||
if last == "OPEN_LONG":
|
||||
self.start = 1
|
||||
elif last == "OPEN_SHORT":
|
||||
self.start = -1
|
||||
else:
|
||||
self.start = 0
|
||||
|
||||
return True
|
||||
except:
|
||||
time.sleep(1)
|
||||
|
||||
return False
|
||||
|
||||
# -------------------------------------------------------
|
||||
# 信号判断:包住形态
|
||||
# -------------------------------------------------------
|
||||
def check_signal(self, prev, curr):
|
||||
p_open, p_close = prev["open"], prev["close"]
|
||||
c_open, c_close = curr["open"], curr["close"]
|
||||
|
||||
# 前跌后涨包住 → 多
|
||||
if is_bearish(prev) and is_bullish(curr) and c_open <= p_close and c_close >= p_open:
|
||||
return "long"
|
||||
|
||||
# 前涨后跌包住 → 空
|
||||
if is_bullish(prev) and is_bearish(curr) and c_open >= p_close and c_close <= p_open:
|
||||
return "short"
|
||||
|
||||
return None
|
||||
|
||||
# -------------------------------------------------------
|
||||
# 下单逻辑
|
||||
# -------------------------------------------------------
|
||||
def place_order(self):
|
||||
# 刷新余额
|
||||
balance = self.get_balance()
|
||||
if not balance:
|
||||
self.send_msg("获取余额失败", err=True)
|
||||
return
|
||||
|
||||
amount = float(balance) / 100
|
||||
self.page.ele('x://input[@placeholder="请输入数量"]').input(amount)
|
||||
time.sleep(1)
|
||||
|
||||
# 开仓和平仓统一逻辑
|
||||
def click(btn_text):
|
||||
self.page.ele(f'x://*[contains(text(), "{btn_text}")]').click()
|
||||
|
||||
if self.direction == "long":
|
||||
if self.start == 0:
|
||||
click("买入开多")
|
||||
self.send_msg(f"开多:{amount}")
|
||||
self.start = 1
|
||||
elif self.start == -1:
|
||||
click("闪电平仓")
|
||||
time.sleep(2)
|
||||
click("买入开多")
|
||||
self.send_msg(f"反手做多:{amount}")
|
||||
self.start = 1
|
||||
|
||||
elif self.direction == "short":
|
||||
if self.start == 0:
|
||||
click("卖出开空")
|
||||
self.send_msg(f"开空:{amount}")
|
||||
self.start = -1
|
||||
elif self.start == 1:
|
||||
click("闪电平仓")
|
||||
time.sleep(2)
|
||||
click("卖出开空")
|
||||
self.send_msg(f"反手做空:{amount}")
|
||||
self.start = -1
|
||||
|
||||
# -------------------------------------------------------
|
||||
# 主执行循环
|
||||
# -------------------------------------------------------
|
||||
def action(self):
|
||||
# 1. 打开浏览器
|
||||
if not self.open_browser():
|
||||
logger.error("无法打开比特浏览器")
|
||||
return
|
||||
|
||||
# 2. 接管浏览器
|
||||
if not self.takeover_browser():
|
||||
logger.error("接管浏览器失败")
|
||||
return
|
||||
|
||||
# 3. 打开交易页
|
||||
self.page.get("https://www.weeaxs.site/zh-CN/futures/ETH-USDT")
|
||||
|
||||
self.pbar = tqdm(total=30, desc="等待中", ncols=80)
|
||||
|
||||
while True:
|
||||
minute = datetime.datetime.now().minute
|
||||
|
||||
# 更新进度条
|
||||
self.pbar.n = minute if minute < 30 else minute - 30
|
||||
self.pbar.refresh()
|
||||
|
||||
# 非关键时间跳过
|
||||
if minute not in {0, 1, 2, 3, 4, 5, 30, 31, 32, 33, 34, 35}:
|
||||
time.sleep(10)
|
||||
continue
|
||||
|
||||
# 避免同一分钟重复操作
|
||||
if self.kline_3 and self.last_action_time == self.kline_3["id"]:
|
||||
continue
|
||||
|
||||
# 获取新 token
|
||||
if not self.get_token():
|
||||
self.send_msg("获取 token 失败", err=True)
|
||||
continue
|
||||
|
||||
# 获取 K 线
|
||||
prices = self.get_price()
|
||||
if not prices:
|
||||
self.send_msg("获取价格失败", err=True)
|
||||
continue
|
||||
|
||||
self.kline_1, self.kline_2, self.kline_3 = prices[-3:]
|
||||
|
||||
self.last_action_time = self.kline_3["id"]
|
||||
|
||||
# 获取仓位状态
|
||||
if not self.get_position():
|
||||
self.send_msg("获取仓位状态失败", err=True)
|
||||
continue
|
||||
|
||||
# 止损逻辑
|
||||
try:
|
||||
if self.start == 1 and is_bearish(self.kline_1) and is_bearish(self.kline_2):
|
||||
self.send_msg("平多")
|
||||
self.page.ele('x://*[contains(text(), "闪电平仓")]').click()
|
||||
self.start = 0
|
||||
|
||||
if self.start == -1 and is_bullish(self.kline_1) and is_bullish(self.kline_2):
|
||||
self.send_msg("平空")
|
||||
self.page.ele('x://*[contains(text(), "闪电平仓")]').click()
|
||||
self.start = 0
|
||||
except:
|
||||
self.send_msg("止损出错", err=True)
|
||||
continue
|
||||
|
||||
# 判断信号
|
||||
self.direction = self.check_signal(self.kline_1, self.kline_2)
|
||||
|
||||
# 执行下单
|
||||
if self.direction:
|
||||
try:
|
||||
self.place_order()
|
||||
except Exception as e:
|
||||
self.send_msg(f"下单失败:{e}", err=True)
|
||||
|
||||
# 推送当前状态
|
||||
self.send_msg(f"持仓:{self.start},信号:{self.direction or '无'}")
|
||||
|
||||
# 重置进度条
|
||||
self.pbar.reset()
|
||||
|
||||
|
||||
# ----------------------------------------------
|
||||
# 程序主入口
|
||||
# ----------------------------------------------
|
||||
if __name__ == '__main__':
|
||||
WeexTransaction(tge_id=146473).action()
|
||||
Reference in New Issue
Block a user