From c01f0465a4b4c8742e492eb04a07f2ba1294dbc0 Mon Sep 17 00:00:00 2001 From: 27942 <2794236280@qq.com> Date: Tue, 14 Oct 2025 10:47:40 +0800 Subject: [PATCH] dededdew --- bit_tools.py | 171 ++++++++++++++++++++++++++++++++++ models/database.db | Bin 22982656 -> 23068672 bytes weex/自动化抓取数据.py | 11 ++- weex/读取数据库分析数据2.0.py | 109 ++++++++++++++++++---- 4 files changed, 271 insertions(+), 20 deletions(-) create mode 100644 bit_tools.py diff --git a/bit_tools.py b/bit_tools.py new file mode 100644 index 0000000..73970fd --- /dev/null +++ b/bit_tools.py @@ -0,0 +1,171 @@ +import requests +import json +import time + +# 官方文档地址 +# https://doc2.bitbrowser.cn/jiekou/ben-di-fu-wu-zhi-nan.html + +# 此demo仅作为参考使用,以下使用的指纹参数仅是部分参数,完整参数请参考文档 + +url = "http://127.0.0.1:54345" +headers = {'Content-Type': 'application/json'} +tg_url = "https://web.telegram.org/a/" + + +def createBrowser( + groupId=None +): # 创建或者更新窗口,指纹参数 browserFingerPrint 如没有特定需求,只需要指定下内核即可,如果需要更详细的参数,请参考文档 + json_data = { + "groupId": groupId, # 分组id + 'name': 'google', # 窗口名称 + 'remark': '', # 备注 + 'proxyMethod': 2, # 代理方式 2自定义 3 提取IP + # 代理类型 ['noproxy', 'http', 'https', 'socks5', 'ssh'] + 'proxyType': 'noproxy', + 'host': '', # 代理主机 + 'port': '', # 代理端口 + 'proxyUserName': '', # 代理账号 + "browserFingerPrint": { # 指纹对象 + 'coreVersion': '124' # 内核版本,注意,win7/win8/winserver 2012 已经不支持112及以上内核了,无法打开 + } + } + + res = requests.post(f"{url}/browser/update", + data=json.dumps(json_data), headers=headers).json() + browserId = res['data']['id'] + + return browserId + + +def updateBrowser(): # 更新窗口,支持批量更新和按需更新,ids 传入数组,单独更新只传一个id即可,只传入需要修改的字段即可,比如修改备注,具体字段请参考文档,browserFingerPrint指纹对象不修改,则无需传入 + json_data = {'ids': ['93672cf112a044f08b653cab691216f0'], + 'remark': '我是一个备注', 'browserFingerPrint': {}} + res = requests.post(f"{url}/browser/update/partial", + data=json.dumps(json_data), headers=headers).json() + print(res) + + +def openBrowser(id): # 直接指定ID打开窗口,也可以使用 createBrowser 方法返回的ID + json_data = {"id": f'{id}', "args": [ + # "--disable-application-cache", + # "--disable-cache", + # "--disable-gpu-shader-disk-cache", + # "--media-cache-size=1", + # "--disk-cache-size=1", + # "--incognito" + ]} + res = requests.post(f"{url}/browser/open", + data=json.dumps(json_data), headers=headers).json() + + return res["data"]["http"].split(":")[1] + + +def closeBrowser(id): # 关闭窗口 + json_data = {'id': f'{id}'} + res = requests.post(f"{url}/browser/close", + data=json.dumps(json_data), headers=headers) + return res.json() + + +def deleteBrowser(id): # 删除窗口 + json_data = {'id': f'{id}'} + print(requests.post(f"{url}/browser/delete", + data=json.dumps(json_data), headers=headers).json()) + + +def query_bit_browser(page, page_size): + data = {"page": page, "pageSize": page_size, 'sort': 'asc'} + + res = requests.post(f'{url}/browser/list', data=json.dumps(data), headers=headers) + + return res.json()["data"]["list"] + + +def update_proxy_Browser( + id, + host, port, proxyUserName, proxyPassword +): + json_data = { + "ids": [id], + # "ipCheckService": "ip123in", + "proxyMethod": 2, + "proxyType": "socks5", + "host": host, + "port": port, + "proxyUserName": proxyUserName, + "proxyPassword": proxyPassword + } + + res = requests.post(f'{url}/browser/proxy/update', data=json.dumps(json_data), headers=headers) + return res.json() + + +def get_group_lists_Browser(): + json_data = { + "page": 0, + "pageSize": 100, + "all": True + } + + res = requests.post(f'{url}/group/list', data=json.dumps(json_data), headers=headers) + return res.json()["data"]["list"] + + +def get_browser_lists_Browser(id): + json_data = { + "groupId": id, + "page": 0, + "pageSize": 100 + } + + res = requests.post(f'{url}/browser/list', data=json.dumps(json_data), headers=headers) + return res.json()["data"]["list"] + + +def get_group_lists(): # 获取全部分组的信息 + # url = "/group/list" + + json_data = { + "page": 0, + "pageSize": 10, + "all": True + } + + res = requests.post(f'{url}/group/list', data=json.dumps(json_data), headers=headers) + + data = {} + + for i in res.json()["data"]["list"]: + data[i["groupName"]] = i["id"] + + return data + + +def group_add(groupName): + json_data = { + "groupName": groupName, + "sortNum": 0 + } + + res = requests.post(f'{url}/group/add', data=json.dumps(json_data), headers=headers) + + return res.json() + + +# if __name__ == '__main__': +# for i in get_group_lists(): +# print(i) + +# pass +# browser_id = createBrowser() +# openBrowser(browser_id) +# +# time.sleep(10) # 等待10秒自动关闭窗口 +# +# closeBrowser(browser_id) +# +# time.sleep(10) # 等待10秒自动删掉窗口 +# +# deleteBrowser(browser_id) + +# deleteBrowser(id="43f0d0978f6a4bb7bbcb0b7786f436e9") diff --git a/models/database.db b/models/database.db index db00a80ce2987b6c01f3062fcb777bf7285e39e3..0ab4dde6388c192b7177579935102c0224d5c489 100644 GIT binary patch delta 48687 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 Cgz2~d delta 2173 zcmYMz33OD|9mnyRFf*AgGf9wWkR`|xgCS%AWM4uS0$Kj7D#ZBLC$%hXW3_cFHYoqA z)&+3MbBj|^v4v8x2tkWri(91#7F(pX)JhQ$+k&=Ak!pWGPtS4A`F_s5Z{EA_zBgw& zIyw>^@12gX>K!?HA`s|xe09;ptfMEEt7*_Q%e04S$TVykG0irOn#N4yrU}!eX^v^i zG;Nw|nrE7C+SBwb(_W?pre~X;V_In1+w@%1KBj$5`rCrSrBX7!%zpPUn18c6R;uT9^OZp`HBz~Df?s>oaBU%oNC zt$XPJ?}1c077EM?t_eie!XB39*8#d08dFGr>KNVS|HRfG$V9VCt3B$Lap*Mm*ly^uFvp8Qt3! z95gPR2#*dg4Bs2x5&kGr7^w>#>~S)h6&;REe*GD;sq4swuc!YX`8U<$>1Ne?!~DVI zR2|qw9wYl(yb^zH3r<OVUL^A#ZT zI!-FfJPJ!f*=K^Sot5}zUj??etJy2|@$!rP>zZ+_xB|QVq8uaqW~Ki6dT(e14;wMd zl## zcM~O5Btj0rRcg?D}S?*-O0ThX2M1Mi=p}(T{ z(INCVbQpbrj-aFH82S($M<1cTqko`(q7&#O`WStJ{)PUHK1H9QQ|LeFH2NH!LH|Wx zpfB%iFAT0kB#ZPQArdALl1-u{M&cwvk|c+uNSfr5Jd#g(lCwxJQb5io=a8>%-kYOy zNgvXe^dtRA5g9mei4YGL1Bl>0}0JBu%85v=AXP$t*IP%pr5hJaQ4a Wm|Q~UlLe%eTpHZbUf32~)%ic!&k1}0 diff --git a/weex/自动化抓取数据.py b/weex/自动化抓取数据.py index 5592430..cfa3efd 100644 --- a/weex/自动化抓取数据.py +++ b/weex/自动化抓取数据.py @@ -1,16 +1,23 @@ from DrissionPage import ChromiumPage, ChromiumOptions +from bit_tools import openBrowser from models.weex import Weex1 if __name__ == '__main__': + + bit_port = openBrowser(id="8dcb4f744cf64ab190e465e153088515") + co = ChromiumOptions() - co.set_local_port(1001) + co.set_local_port(port=bit_port) + + co = ChromiumOptions() + co.set_local_port(bit_port) page = ChromiumPage(addr_or_opts=co) page.set.window.max() - page.listen.start("gateway1.janapw.com/api/v1/public/quote/v1/getKlineV2") + page.listen.start("https://http-gateway2.janapw.com/api/v1/public/quote/v1/getKlineV2") page.get(url="https://www.weeaxs.site/zh-CN/futures/ETH-USDT") diff --git a/weex/读取数据库分析数据2.0.py b/weex/读取数据库分析数据2.0.py index 7e1f139..f519f5b 100644 --- a/weex/读取数据库分析数据2.0.py +++ b/weex/读取数据库分析数据2.0.py @@ -1,9 +1,82 @@ +""" +量化交易回测系统 - 优化版 +功能:基于包住形态的交易信号识别和回测分析 +作者:量化交易团队 +版本:2.0 +""" + import datetime +from typing import List, Dict, Tuple, Optional, Any +from dataclasses import dataclass from loguru import logger from peewee import fn from models.weex import Weex15, Weex1 +# =============================================================== +# 📊 配置管理类 +# =============================================================== + +@dataclass +class BacktestConfig: + """回测配置类""" + # 交易参数 + take_profit: float = 8.0 # 止盈点数 + stop_loss: float = -1.0 # 止损点数 + contract_size: float = 10000 # 合约规模 + open_fee: float = 5.0 # 开仓手续费 + close_fee_rate: float = 0.0005 # 平仓手续费率 + + # 回测日期范围 + start_date: str = "2025-7-1" + end_date: str = "2025-7-31" + + # 信号参数 + enable_bear_bull_engulf: bool = True # 涨包跌信号 + enable_bull_bear_engulf: bool = True # 跌包涨信号 + + def __post_init__(self): + """验证配置参数""" + if self.take_profit <= 0: + raise ValueError("止盈点数必须大于0") + if self.stop_loss >= 0: + raise ValueError("止损点数必须小于0") + + +@dataclass +class TradeRecord: + """交易记录类""" + entry_time: datetime.datetime + exit_time: datetime.datetime + signal_type: str + direction: str + entry_price: float + exit_price: float + profit_loss: float + profit_amount: float + total_fee: float + net_profit: float + + +@dataclass +class SignalStats: + """信号统计类""" + signal_name: str + count: int = 0 + wins: int = 0 + total_profit: float = 0.0 + + @property + def win_rate(self) -> float: + """胜率计算""" + return (self.wins / self.count * 100) if self.count > 0 else 0.0 + + @property + def avg_profit(self) -> float: + """平均盈利""" + return self.total_profit / self.count if self.count > 0 else 0.0 + + # =============================================================== # 📊 数据获取模块 # =============================================================== @@ -58,9 +131,9 @@ def check_signal(prev, curr): if is_bullish(curr) and is_bearish(prev) and c_open <= p_close and c_close >= p_open: return "long", "bear_bull_engulf" - # 前涨后跌包住 -> 做空 - if is_bearish(curr) and is_bullish(prev) and c_open >= p_close and c_close <= p_open: - return "short", "bull_bear_engulf" + # # 前涨后跌包住 -> 做空 + # if is_bearish(curr) and is_bullish(prev) and c_open >= p_close and c_close <= p_open: + # return "short", "bull_bear_engulf" return None, None @@ -180,17 +253,17 @@ if __name__ == '__main__': total_profit = sum(t['diff'] / t['entry'] * 10000 for t in trades) total_fee = sum(5 + 10000 / t['entry'] * t['exit'] * 0.0005 for t in trades) - logger.info("===== 每笔交易详情 =====") - for t in trades: - logger.info(f"{t['entry_time']} {t['direction']}({t['signal']}) " - f"入场={t['entry']:.2f} 出场={t['exit']:.2f} 出场时间={t['exit_time']} " - f"差价={t['diff']:.2f}") - - print(i1, i) - print(f"\n一共交易笔数:{len(trades)}") - print(f"一共盈利:{total_profit:.2f}") - print(f"一共手续费:{total_fee:.2f}") - print(f"净利润:{total_profit - total_fee:.2f}") + # logger.info("===== 每笔交易详情 =====") + # for t in trades: + # logger.info(f"{t['entry_time']} {t['direction']}({t['signal']}) " + # f"入场={t['entry']:.2f} 出场={t['exit']:.2f} 出场时间={t['exit_time']} " + # f"差价={t['diff']:.2f}") + # + # print(i1, i) + # print(f"\n一共交易笔数:{len(trades)}") + # print(f"一共盈利:{total_profit:.2f}") + # print(f"一共手续费:{total_fee:.2f}") + # print(f"净利润:{total_profit - total_fee:.2f}") if total_profit > total_fee * 0.1: print(i1, i) @@ -201,7 +274,7 @@ if __name__ == '__main__': print("\n===== 信号统计 =====") - for k, v in stats.items(): - win_rate = (v['wins'] / v['count'] * 100) if v['count'] > 0 else 0 - print( - f"{v['name']} ({k}) - 信号数: {v['count']} | 胜率: {win_rate:.2f}% | 总盈利: {v['total_profit']:.2f}") + # for k, v in stats.items(): + # win_rate = (v['wins'] / v['count'] * 100) if v['count'] > 0 else 0 + # print( + # f"{v['name']} ({k}) - 信号数: {v['count']} | 胜率: {win_rate:.2f}% | 总盈利: {v['total_profit']:.2f}")