diff --git a/1.交易策略/999.其他策略/4.松鼠SF20_基于LLM的订单流日内交易策略/使用文档/3.28版本/AI智能订单流交易策略图文解析.md b/1.交易策略/999.其他策略/4.松鼠SF20_基于LLM的订单流日内交易策略/使用文档/3.28版本/AI智能订单流交易策略图文解析.md new file mode 100644 index 0000000..e3046af --- /dev/null +++ b/1.交易策略/999.其他策略/4.松鼠SF20_基于LLM的订单流日内交易策略/使用文档/3.28版本/AI智能订单流交易策略图文解析.md @@ -0,0 +1,468 @@ +# AI智能订单流交易策略图文解析 + +## 一、系统整体架构 + +AI智能订单流交易策略是一套融合高频数据分析与人工智能决策的自动化期货交易系统。该系统通过分析市场微观结构特征,结合大模型AI的综合分析能力,实现从市场监控到交易执行的全流程智能化。 + +该交易系统基于python的CTP接口开发,采用多进程架构,实现了行情数据处理、订单流分析、AI决策和交易执行的全流程自动化。系统架构主要包括: + +``` +主程序 +├── 行情进程 (run_tick_engine) +│ └── Tick数据处理 +└── 交易进程 (run_trader) + ├── MyTrader类 + │ ├── 交易逻辑处理 + │ ├── 止损止盈管理 + │ └── 日内平仓控制 + └── AI分析线程 (background_model_call) +``` + +### 系统架构图 + +``` +┌───────────────────────┐ +│ 主程序入口 │ +└───────────┬───────────┘ + │ + ┌──────┴──────┐ + ▼ ▼ +┌─────────┐ ┌─────────┐ +│行情进程 │ │交易进程 │ +└────┬────┘ └────┬────┘ + │ │ + ▼ ▼ +┌─────────┐ ┌─────────────┐ +│Tick处理 │ │ MyTrader类 │ +└────┬────┘ └──────┬──────┘ + │ │ + ▼ ▼ +┌─────────┐ ┌───────────┐ ┌───────────┐ +│K线构建 │ │交易信号处理│ ←── │ AI分析线程│ +└────┬────┘ └──────┬────┘ └───────────┘ + │ │ + ▼ ▼ +┌─────────┐ ┌───────────┐ +│订单流分析│ │风险管理系统│ +└─────────┘ └───────────┘ +``` + +系统采用多进程架构设计,主要分为两个核心进程: + +1. **行情进程**:负责接收和处理实时市场数据 + - Tick数据处理 + - K线构建 + - 订单流分析 + +2. **交易进程**:负责交易决策与执行 + - AI模型分析(异步线程) + - 交易信号处理 + - 风险管理系统 + - 订单执行 + +这种架构设计有效分离了数据处理和交易执行,确保系统稳定性和响应速度。 + +## 二、核心数据流程 + +### 数据流向图 + +``` +┌───────────┐ ┌───────────┐ ┌───────────┐ ┌───────────┐ +│ CTP接口 │ → │ Tick数据 │ → │ K线数据 │ → │订单流分析 │ +└───────────┘ └───────────┘ └───────────┘ └─────┬─────┘ + │ +┌───────────┐ ┌───────────┐ ┌───────────┐ │ +│订单执行系统│ ← │交易信号生成│ ← │ AI决策分析│ ← ────┘ +└───────────┘ └───────────┘ └───────────┘ +``` + +系统数据处理的完整流程如下: + +1. **Tick数据接收**:从CTP接口获取实时行情数据 +2. **K线构建**:将Tick数据聚合成分钟级K线 +3. **订单流分析**:计算Delta值和堆积指标 +4. **AI模型分析**:利用大模型分析市场状态 +5. **交易信号生成**:生成包含方向、置信度和风控参数的信号 +6. **订单执行**:根据信号执行交易策略 + +## 三、订单流分析详解 + +订单流分析是该系统的核心特色,它通过分析每一笔成交背后的买卖意图,揭示常规技术分析无法察觉的市场微观结构。 + +### 订单流原理图 + +``` +价格 + ▲ + │ ┌────┐ + │ │ │ + │ ┌───┘ └───┐ + │ │ │ + │ │ └───┐ + │ │ │ + │ │ │ + └───┴─────────────────┴────────► 时间 + ↑ ↑ ↑ ↑ + │ │ │ │ + +5 -3 +8 -2 ← Delta值 + │ │ │ │ + └─────┴─────┴─────┘ + │ + Delta累计 = +8 +``` + +订单流分析的核心概念: + +#### 1. Delta值计算 + +Delta值表示主动买入成交量与主动卖出成交量的差值: + +- **主动买入**:成交价 ≥ 卖一价时的成交 +- **主动卖出**:成交价 ≤ 买一价时的成交 +- **Delta = 主动买入量 - 主动卖出量** + +系统中这部分实现的关键代码: + +```python +# 判断交易是主动买入还是主动卖出 +if LastPrice >= Ap: # 高于卖一价成交,视为主动买入 + askDict[str(LastPrice)] += Volume +if LastPrice <= Bp: # 低于买一价成交,视为主动卖出 + bidDict[str(LastPrice)] += Volume + +# 计算Delta值 +delta = (sum(askDictResult.values()) - sum(bidDictResult.values())) +``` + +#### 2. 堆积指标(DJ) + +堆积指标用于识别主力资金的集中买卖行为,通过分析买卖盘异常大单的堆积现象,发现大资金的布局意图: + +- **多头堆积**:某价位的卖单量远大于邻近价位的买单量 +- **空头堆积**:某价位的买单量远大于邻近价位的卖单量 + +堆积形成的市场意义: +- 多头堆积形成后,价格往往出现上涨 +- 空头堆积形成后,价格往往出现下跌 + +这种微观结构变化,往往领先于价格变动,为交易提供了先机。 + +### 订单流指标解读 + +| 指标名称 | 计算方法 | 市场含义 | 交易信号 | +|---------|---------|---------|---------| +| Delta值 | 主动买入量-主动卖出量 | 单根K线买卖力量对比 | 正值=买方强势,负值=卖方强势 | +| Delta累计 | Delta值的累计曲线 | 资金流向趋势 | 向上倾斜=做多信号,向下倾斜=做空信号 | +| 堆积指标(DJ) | 基于买卖盘大单异常计算 | 大资金买卖意图 | 正值=多头堆积,负值=空头堆积 | +| 买卖比值 | 主动买入量/主动卖出量 | 短期市场情绪 | >1.5买方强势,<0.7卖方强势 | + +## 四、AI决策系统工作流程 + +系统采用DeepSeek大模型作为核心分析引擎,实现类似专业交易员的市场分析和决策能力。 + +### AI决策流程图 + +``` +┌────────────┐ ┌────────────┐ ┌────────────┐ +│ 市场数据整合 │ ──► │ 数据格式化 │ ──► │ 提示词构建 │ +└──────┬─────┘ └──────┬─────┘ └──────┬─────┘ + │ │ │ + └──────────────────┼──────────────────┘ + │ + ▼ +┌────────────┐ ┌────────────┐ ┌────────────┐ +│ 交易信号执行 │ ◄── │ 信号质量检查 │ ◄── │ 大模型API调用│ +└────────────┘ └────────────┘ └────────────┘ +``` + +#### 1. 数据格式化 + +系统通过`format_data_for_llm`方法将市场数据转换为文本格式,供AI模型分析: + +```python +data_text = "订单流数据分析:\n\n" +data_text += f"当前时间: {recent_data['datetime'].iloc[-1]}\n" +data_text += f"当前价格: {recent_data['close'].iloc[-1]}\n" +data_text += f"MA5: {ma5:.2f}\n" +data_text += f"MA10: {ma10:.2f}\n" +data_text += f"MA20: {ma20:.2f}\n" +data_text += f"订单流净值: {recent_data['delta'].iloc[-1]}\n" +data_text += f"堆积指标: {recent_data['dj'].iloc[-1]}\n" +# ...更多市场数据... +``` + +#### 2. AI分析要素 + +AI模型会综合分析以下关键因素: + +- **技术形态**:均线排列、K线形态、支撑阻力位 +- **订单流特征**:Delta趋势、堆积情况、买卖力量对比 +- **市场状态**:超买超卖、波动性、当前位置 +- **趋势强度**:价格动量、趋势持续性 +- **当前持仓**:持仓状态、盈亏情况、风险敞口 + +#### 3. 交易信号格式 + +AI模型返回的交易信号包含以下要素: + +``` +action: 开多/开空/平多/平空/不操作 +reason: 交易理由 +confidence: 置信度(1-10) +stop_loss: 止损价 +take_profit: 止盈价 +trailing_percent: 跟踪止损百分比 +``` + +例如,当系统检测到强势上涨趋势时,可能生成如下信号: + +``` +action: 开多 +reason: 均线形成多头排列,价格突破前期高点,订单流Delta累计持续走高 +confidence: 8 +stop_loss: 4382 +take_profit: 4425 +trailing_percent: 0.006 +``` + +#### 4. 信号质量控制 + +为确保交易信号的可靠性,系统采用多重过滤机制: + +- **置信度阈值**:只有置信度≥6的信号才会执行 +- **时效性检查**:超过15秒的信号将被忽略 +- **市场适应性**:AI会根据不同市场环境给出不同置信度 + +## 五、风险管理系统 + +风险控制是交易系统的生命线,本系统采用三层防护的止损体系。 + +### 风险管理层次图 + +``` +┌─────────────────────────────────────────┐ +│ 风险管理系统 │ +└───────────────┬─────────────────────────┘ + │ + ┌───────────┴───────────┐ + │ │ +┌───▼───┐ ┌────▼───┐ +│止损系统│ │平仓系统 │ +└───┬───┘ └────┬───┘ + │ │ + ▼ ▼ +┌───────────────┐ ┌──────────────┐ +│ 固定止损 │ │ 日内自动平仓 │ +└───────────────┘ └──────────────┘ +┌───────────────┐ ┌──────────────┐ +│ 跟踪止损 │ │ 反向信号平仓 │ +└───────────────┘ └──────────────┘ +┌───────────────┐ ┌──────────────┐ +│ AI动态止损 │ │ AI指令平仓 │ +└───────────────┘ └──────────────┘ +``` + +#### 1. 固定止损 + +固定止损是最基本的风险控制措施,在开仓时就设定了明确的止损价格: + +- **多头止损**:开仓价 × (1 - fixed_stop_loss_percent) +- **空头止损**:开仓价 × (1 + fixed_stop_loss_percent) + +默认固定止损比例为1%,可根据不同品种波动性调整。 + +#### 2. 跟踪止损 + +跟踪止损能够在保留利润空间的同时,为交易提供风险保护: + +```python +# 更新多头跟踪止损价 - 只在价格上涨时更新 +if stops['long']['trailing_stop'] > 0: + new_trailing_stop = current_bid * (1 - self.trailing_stop_percent) + if new_trailing_stop > stops['long']['trailing_stop']: + self.update_stop_order_dict(instrument_id, 'long', None, None, None, None, new_trailing_stop) +``` + +跟踪止损的工作原理: +- 随着价格向有利方向移动,止损价位也相应调整 +- 当价格回撤超过设定的百分比时,触发止损 +- 默认跟踪止损比例为0.5%,由AI模型根据市场波动性动态调整 + +#### 3. 日内平仓机制 + +系统设有日内自动平仓功能,避免隔夜风险: + +- **收盘平仓时间**:15:00-15:15 或 23:00-23:15 +- **平仓逻辑**:强制平掉所有持仓,无论盈亏 +- **禁开新仓**:平仓后设置day_closed标志,禁止当日再开新仓 + +## 六、持仓管理与数据存储 + +### 持仓数据结构 + +系统对每个合约独立管理持仓信息,使用嵌套字典结构: + +```python +self.stop_order_dict[instrument_id] = { + 'long': { + 'position': 0, # 多头持仓量 + 'entry_price': 0, # 开仓价格 + 'stop_loss': 0, # 止损价格 + 'take_profit': 0, # 止盈价格 + 'trailing_stop': 0 # 跟踪止损价格 + }, + 'short': { + 'position': 0, # 空头持仓量 + 'entry_price': 0, # 开仓价格 + 'stop_loss': 0, # 止损价格 + 'take_profit': 0, # 止盈价格 + 'trailing_stop': 0 # 跟踪止损价格 + } +} +``` + +### 数据存储结构 + +系统在`traderdata/`目录下保存以下数据文件: + +| 文件名 | 内容 | 用途 | +|-------|-----|------| +| `{合约代码}_ofdata.json` | 订单流历史数据 | 用于回测分析和模型训练 | +| `{合约代码}traderdata.csv` | 持仓和止损止盈数据 | 用于持仓状态恢复 | +| `{合约代码}_stops.json` | 详细止盈止损设置 | 用于风险管理参数存储 | + +这种数据存储设计允许系统在重启后能够恢复交易状态,避免信息丢失。 + +## 七、系统参数优化指南 + +### 关键参数对照表 + +| 参数名称 | 默认值 | 作用 | 调整建议 | +|---------|-------|-----|---------| +| py | 5 | 委托价格偏移量(跳数) | 低波动品种:1-3
高波动品种:5-10 | +| trailing_stop_percent | 0.005 | 跟踪止损百分比(0.5%) | 低波动品种:0.002-0.005
高波动品种:0.008-0.01 | +| fixed_stop_loss_percent | 0.01 | 固定止损百分比(1%) | 低波动品种:0.005-0.01
高波动品种:0.015-0.02 | +| Lots | 1 | 下单手数 | 根据资金量和风险偏好调整 | +| BAR_RESAMPLE_RULE | '1T' | K线时间粒度 | 短线:'1T'(1分钟)
中线:'5T'(5分钟)
长线:'15T'(15分钟) | +| trader_rows | 10 | AI分析触发的最小数据行数 | 高频:5
中频:10
低频:20或更高 | + +### 针对不同品种的优化建议 + +**商品期货(如螺纹钢、铜、原油)**: +- 波动性较大,建议使用较大的止损范围(1.5%-2%) +- K线粒度建议使用1分钟或5分钟 +- 委托价格偏移量设置较大(5-10跳) + +**金融期货(如股指、国债)**: +- 波动性相对较小,建议使用较小的止损范围(0.5%-1%) +- K线粒度建议使用5分钟或15分钟 +- 委托价格偏移量设置较小(1-3跳) + +## 八、常见应用场景 + +### 场景一:趋势突破交易 + +**市场特征**: +- 均线形成多头排列 +- 价格突破重要阻力位 +- 订单流Delta累计呈上升趋势 + +**系统响应**: +- AI识别趋势突破形态,给出高置信度开仓信号 +- 设置前期突破点下方的止损位置 +- 采用较小的跟踪止损比例,让利润奔跑 + +**典型执行流程图**: +``` +价格突破阻力位 → AI分析(8分置信度) → 开多信号 → +设置止损(阻力位下方) → 价格持续上涨 → +跟踪止损上移 → 最终获利平仓 +``` + +### 场景二:超买超卖反转交易 + +**市场特征**: +- 价格处于极端位置(日内位置>85%或<15%) +- 订单流指标与价格出现背离 +- K线形成反转形态(如吞没形态) + +**系统响应**: +- AI模型识别到反转信号,给出开仓建议 +- 设置相对紧密的止损位置 +- 目标价位设为前期支撑/阻力位 + +**典型执行流程图**: +``` +价格极度超买 → 订单流指标转弱 → +AI分析(7分置信度) → 开空信号 → +设置紧密止损 → 价格回落 → 目标价位获利了结 +``` + +## 九、系统优势与局限性 + +### 主要优势 + +1. **微观结构洞察**:通过订单流分析看清市场真实供需状态 +2. **智能决策能力**:大模型AI提供类似专业交易员的分析能力 +3. **自适应参数**:系统能根据市场状态动态调整风控参数 +4. **多层风险控制**:完善的止损体系保障资金安全 +5. **数据持久化**:交易状态保存与恢复机制,确保系统稳定性 + +### 局限性 + +1. **数据质量依赖**:订单流分析对行情数据质量要求较高 +2. **API成本**:大模型API调用存在成本,需考虑经济性 +3. **延迟问题**:AI分析存在延迟,不适合超短线交易 +4. **特殊行情**:在极端行情下,止损可能因滑点而失效 +5. **模型局限**:AI模型对某些特殊市场环境可能缺乏足够认知 + +## 十、操作指南 + +### 运行前准备 + +1. **环境配置**: + - Python 3.7-3.10 + - 安装相关依赖库:AlgoPlus、pandas、numpy、openai等 + - 创建必要的数据存储目录:traderdata/ + +2. **账户配置**: + ```python + # 模拟盘或实盘账户配置 + future_account = get_simulate_account( + investor_id='您的账户ID', + password='您的密码', + server_name='电信1', + subscribe_list=[b'au2506'], # 订阅的合约 + ) + ``` + +3. **API配置**: + ```python + # DeepSeek API配置 + api_key = "您的DeepSeek API密钥" + os.environ["OPENAI_API_KEY"] = api_key + ``` + +### 运行与监控 + +1. **启动系统**: + - 运行主程序文件:`python 实盘运行版本_版本6.py` + - 确认系统连接成功并开始接收数据 + +2. **运行监控**: + - 观察控制台输出的K线数据和订单流分析结果 + - 查看AI模型的分析结果和交易信号 + - 监控持仓状态和止损止盈位置 + +3. **常见问题排查**: + - API连接失败:检查API密钥和网络连接 + - 数据文件读写错误:检查目录权限和磁盘空间 + - 交易信号不执行:检查置信度是否满足阈值要求 + +## 结语 + +AI智能订单流交易策略系统通过融合订单流分析和人工智能决策,为期货交易提供了一套全自动化的解决方案。系统能够捕捉市场微观结构变化,洞察主力资金动向,并结合AI的理解能力做出合理的交易决策。 + +这套系统适合有一定编程和交易基础的用户,可以作为决策辅助工具或全自动交易系统使用。在实际应用中,请务必先在模拟环境中充分测试,并确保完全理解风险管理机制,保证资金安全。 + +**风险提示**:期货交易存在高风险,本系统仅供学习研究使用,实盘交易盈亏自负。请确保充分了解期货交易风险,根据自身风险承受能力谨慎投资。 \ No newline at end of file diff --git a/1.交易策略/999.其他策略/4.松鼠SF20_基于LLM的订单流日内交易策略/使用文档/3.28版本/README.md b/1.交易策略/999.其他策略/4.松鼠SF20_基于LLM的订单流日内交易策略/使用文档/3.28版本/README.md new file mode 100644 index 0000000..0a3ed0a --- /dev/null +++ b/1.交易策略/999.其他策略/4.松鼠SF20_基于LLM的订单流日内交易策略/使用文档/3.28版本/README.md @@ -0,0 +1,433 @@ +# AI智能订单流交易策略详细说明 + +## 项目简介 + +本项目是一个基于订单流分析与大语言模型(LLM)集成的智能期货交易系统,通过AlgoPlus接口对接CTP交易系统,实现全自动化的交易策略执行。系统核心特点是结合高频Tick数据订单流分析与人工智能决策系统,对期货市场进行实时监控、分析和交易。 + +### 技术架构 + +- **数据层**:通过CTP接口获取实时Tick数据 +- **分析层**:订单流分析、K线构建、技术指标计算 +- **决策层**:基于DeepSeek大模型的AI决策系统 +- **执行层**:自动化交易执行系统,包含风险控制模块 + +## 核心功能详解 + +### 1. 订单流数据处理 + +系统处理原始Tick数据,构建以下信息: +- **成交订单流**:分析每个价位的买入/卖出压力 +- **多空资金流向**:计算买卖力量对比指标 +- **堆积指标(DJ)**:识别主力资金大量买入卖出信号 +- **订单流趋势**:分析订单流累计变化趋势 +- **波动性指标**:监控市场情绪变化 + +### 2. 技术分析模块 + +系统自动构建并分析以下技术分析指标: +- **移动平均线**:5、10、20周期均线系统,监控均线形态(多头排列、空头排列、金叉、死叉) +- **K线形态识别**:自动识别大阳线、大阴线、十字星、吞没形态等经典K线组合 +- **趋势强度**:计算价格趋势的强度和持续性 +- **支撑阻力位**:自动识别近期关键价格区域 +- **超买超卖状态**:判断当前价格在日内区间的位置 + +### 3. AI决策系统 + +系统集成了DeepSeek大模型作为核心决策引擎: +- **市场状态识别**:全面分析当前市场环境 +- **交易信号生成**:产生开仓、平仓或调整持仓的信号 +- **风险参数建议**:动态优化止损止盈水平 +- **多层验证机制**:通过置信度评分过滤低质量信号 + +完整的交易决策包含: +- **方向**:开多/开空/平多/平空/不操作 +- **置信度**:1-10分级评估系统 +- **止损价**:推荐的止损位置 +- **止盈价**:推荐的止盈位置 +- **跟踪百分比**:针对当前市场波动性优化的跟踪止损参数 + +### 4. 风险控制系统 + +多层次风险管理机制: +- **固定止损**:基于开仓价设置硬性止损点 +- **跟踪止损**:随价格变动动态调整止损价位,锁定盈利 +- **日内平仓**:自动在交易时段结束前平仓,避免隔夜风险 +- **反向信号管理**:收到反向信号时智能处理现有持仓 +- **资金管理**:控制单笔交易风险占比 + +### 5. 数据存储与分析 + +系统自动保存交易和市场数据: +- **订单流历史数据**:以JSON格式保存,方便后续分析 +- **交易记录**:包含所有成交信息 +- **止损止盈设置**:记录每个合约的风险管理参数 +- **AI决策记录**:保存模型分析结果和建议 + +## 详细系统配置指南 + +### 环境要求 + +- **操作系统**:Windows 7/10/11 或 Linux (Ubuntu 18.04+) +- **Python版本**:Python 3.7-3.10(推荐3.8) +- **内存要求**:至少4GB RAM(推荐8GB以上) +- **存储空间**:至少500MB可用空间 +- **网络要求**:稳定的网络连接,低延迟 + +### 依赖安装 + +```bash +# 安装基础依赖 +pip install AlgoPlus +pip install pandas numpy +pip install python-dateutil + +# 安装AI模型依赖 +pip install openai +pip install requests + +``` + +### 详细配置选项 + +#### 1. 基础交易参数 + +可在`MyTrader`类初始化方法中修改: + +```python +# 基础交易参数 +self.py = 5 # 委托价格偏移量,单位跳数 +self.Lots = 1 # 每次开仓手数 +self.trailing_stop_percent = 0.005 # 跟踪止损百分比(0.5%) +self.fixed_stop_loss_percent = 0.01 # 固定止损百分比(1%) +self.dj_X = 1 # 订单流堆积参数阈值 + +# AI模型控制 +self.use_ai_model = True # 是否启用AI模型 +self.trader_rows = 10 # 触发AI分析的最小数据行数 + +# 日内交易控制 +self.day_closed = False # 日内平仓标志 +``` + +#### 2. 高级参数配置 + +在主程序中设置: + +```python +# 全局参数配置 +GLOBAL_LLM_CONFIG = { + 'api_key': 'your-api-key', # API密钥 + 'base_url': 'https://api.deepseek.com', # API基础URL + 'model_name': 'deepseek-reasoner' # 模型名称 +} + +# K线时间粒度设置 +BAR_RESAMPLE_RULE = '1T' # 1分钟K线 +# 其他可选值: +# '5T' - 5分钟K线 +# '15T' - 15分钟K线 +# '30T' - 30分钟K线 +# '1H' - 1小时K线 +# '4H' - 4小时K线 +# '5S' - 5秒K线 + +# 历史数据加载设置 +LOAD_HISTORY = False # 是否加载历史数据 +HISTORY_ROWS = 30 # 加载历史数据行数 +``` + +#### 3. 主力合约设置 + +在交易账户配置中设置要交易的合约: + +```python +# 模拟盘设置 +future_account = get_simulate_account( + investor_id='您的账户ID', + password='您的密码', + server_name='电信1', + # 订阅多个合约示例 + subscribe_list=[ + b'au2506', # 黄金主力合约 + b'rb2410', # 螺纹钢主力合约 + b'IF2406', # 沪深300指数期货主力合约 + b'cu2407' # 铜主力合约 + ], +) +``` + +## 详细使用指南 + +### 首次运行前准备 + +1. **创建必要目录**: + ```bash + mkdir -p traderdata logs + ``` + +2. **API密钥配置**: + 确保在代码中配置了正确的DeepSeek API密钥: + ```python + api_key = "您的API密钥" + os.environ["OPENAI_API_KEY"] = api_key + ``` + +3. **账户检查**: + - 模拟账户:确认Simnow账户可正常登录 + - 实盘账户:确认资金足够,交易权限已开通 + +4. **合约选择**: + - 建议从流动性好的品种开始,如螺纹钢(rb)、黄金(au)、沪深300(IF) + - 确保所选合约处于交易时段 + +### 运行系统 + +1. **启动主程序**: + ```bash + python 实盘运行版本_版本6.py + ``` + +2. **启动确认**: + - 确认系统显示"API连接测试成功" + - 确认系统正确连接到CTP服务器 + - 确认接收到Tick数据 + +3. **监控运行状态**: + - 观察新K线形成和订单流数据生成 + - 观察AI模型分析结果 + - 监控交易执行和持仓状态 + +### 高级操作指南 + +#### 多合约交易管理 + +系统支持同时监控多个合约,对每个合约独立生成交易信号和执行交易: + +1. **风险分散**:建议同时监控多个相关性低的品种 +2. **资金分配**:可通过调整`self.Lots`参数控制各合约下单手数 +3. **单独配置**:每个合约的止损止盈设置独立保存和管理 + +#### 自定义止损止盈策略 + +系统提供了多种止损止盈机制,可以根据不同市场环境调整: + +1. **固定止损**:适合趋势明确的市场 + ```python + self.fixed_stop_loss_percent = 0.01 # 1%止损 + ``` + +2. **跟踪止损**:适合波动较大的市场 + ```python + self.trailing_stop_percent = 0.005 # 0.5%跟踪止损 + ``` + +3. **动态止损**:由AI模型根据市场状态动态调整 + - 系统会根据波动性自动建议0.0001-0.001范围内的跟踪止损参数 + +#### 回测与优化 + +虽然本系统主要面向实盘交易,但可以通过以下方式进行策略评估: + +1. **离线数据分析**: + - 查看`traderdata/{合约代码}_ofdata.json`中的历史数据和AI决策记录 + - 分析交易成功率和盈亏比 + +2. **参数优化**: + - 针对不同品种调整`self.py`委托价格偏移量 + - 针对不同波动性市场调整止损止盈参数 + - 调整`trader_rows`参数控制AI分析触发频率 + +## 技术架构详解 + +### 多进程架构 + +系统采用多进程设计,实现行情和交易的分离: +- **行情进程**:专注于数据接收和处理 +- **交易进程**:负责交易决策和执行 +- **AI分析线程**:在后台异步运行,不阻塞主交易流程 + +``` +主程序 +│ +├── 行情进程 (run_tick_engine) +│ └── Tick数据处理 +│ ├── 构建K线 +│ └── 计算订单流指标 +│ +└── 交易进程 (run_trader) + ├── MyTrader实例 + │ ├── 交易逻辑处理 + │ ├── 止损止盈管理 + │ └── 日内平仓控制 + │ + └── AI分析线程 (background_model_call) + └── 交易信号生成 +``` + +### 数据流向 + +系统数据流向设计清晰,各模块职责明确: + +``` +CTP行情接口 → Tick数据 → K线构建 → 订单流分析 + ↓ +交易执行 ← 交易信号 ← AI模型分析 ← 市场数据融合 +``` + +### 核心类解析 + +#### `MyTrader`类 + +继承自`TraderApiBase`,实现以下核心功能: +- 处理交易回报和订单状态 +- 管理持仓和风险控制 +- 协调AI模型交易决策 +- 执行交易指令 + +关键方法: +- `background_model_call`:调用AI模型进行分析 +- `check_stop_conditions`:检查止损止盈条件 +- `clear_position_info`:清理持仓信息 +- `format_data_for_llm`:格式化数据供AI模型分析 + +#### AI决策系统 + +`call_deepseek_model`函数负责调用DeepSeek大模型: +- 采用重试机制确保API调用可靠性 +- 解析AI模型返回的交易信号 +- 处理异常情况和错误 + +## 故障排除 + +### 常见问题与解决方案 + +1. **CTP连接问题** + - **症状**:无法连接到CTP服务器或频繁断连 + - **解决方案**: + - 检查网络连接稳定性 + - 确认服务器地址和端口正确 + - 检查账户密码是否正确 + +2. **AI模型调用失败** + - **症状**:"API调用失败"错误 + - **解决方案**: + - 验证API密钥有效性 + - 检查网络能否访问DeepSeek API + - 查看是否达到API调用限制 + +3. **数据文件读写错误** + - **症状**:"读取或保存JSON文件时出错" + - **解决方案**: + - 确认traderdata目录存在且有写权限 + - 检查磁盘空间是否充足 + - 确保没有其他程序锁定目标文件 + +4. **交易执行问题** + - **症状**:交易信号生成但未执行 + - **解决方案**: + - 检查置信度是否达到执行阈值(≥6) + - 确认是否在交易时段内 + - 确认是否有足够可用资金 + +### 日志与调试 + +系统提供详细的控制台输出用于监控和调试: + +``` +===== 开始AI分析 [15:30:45] ===== +正在分析合约: au2506 +分析数据行数: 25 +最新价格: 486.35 +... +AI模型分析完成,结果已放入队列,耗时: 5.32秒 +分析结果: {'action': '开多', 'confidence': 8, 'reason': '订单流持续为正...'} +===== AI分析完成 ===== + +===== 执行AI模型交易信号 [15:30:53] ===== +信号生成时间: 15:30:50 +信号类型: 开多 +置信度: 8 +理由: 订单流持续为正... +... +执行开多操作 +设置止损价: 482.35, 止盈价: 489.28, 跟踪止损价: 483.72, 跟踪百分比: 0.500% +===== 交易信号执行完成 ===== +``` + +## 性能优化建议 + +1. **降低API调用频率**: + - 增加`trader_rows`参数值,减少AI模型调用频率 + - 在低波动时段可考虑暂时禁用AI分析 + +2. **优化数据存储**: + - 定期清理过时的历史数据文件 + - 使用更高效的数据结构和存储格式 + +3. **减少不必要的计算**: + - 调整K线时间粒度,避免过于频繁的处理 + - 针对性能瓶颈部分进行代码优化 + +## 进阶开发指南 + +### 自定义扩展 + +系统设计具有良好的扩展性,可以在以下方面进行自定义开发: + +1. **增加新的技术指标**: + 在`format_data_for_llm`方法中添加新的技术分析指标 + +2. **优化订单流算法**: + 修改`GetOrderFlow_dj`函数,实现更精细的订单流分析 + +3. **扩展风险管理策略**: + 在`check_stop_conditions`中实现更复杂的止损止盈策略 + +4. **自定义AI提示词**: + 修改`call_deepseek_model`函数中的prompt变量,优化AI分析效果 + +### 集成其他AI模型 + +除了默认的DeepSeek模型,系统架构支持集成其他AI服务: + +```python +# 使用其他LLM服务示例 +def call_alternative_model(data_df, trader_instance): + # 配置新的客户端 + client = AlternativeClient(api_key="your-api-key") + + # 准备数据 + data_text = trader_instance.format_data_for_llm(data_df) + + # 调用API + response = client.chat(prompt=data_text) + + # 解析结果 + trading_signal = parse_response(response) + + return trading_signal +``` + +## 资产风险声明 + +本交易系统仅供学习和研究使用,实际交易存在以下风险: + +1. **市场风险**:期货市场波动可能导致重大损失 +2. **系统风险**:软件故障、网络延迟等可能影响交易执行 +3. **模型风险**:AI分析并非100%准确,可能做出错误判断 +4. **流动性风险**:某些合约在特定时段可能缺乏足够流动性 +5. **操作风险**:参数设置不当可能导致意外损失 + +使用本系统进行实盘交易,盈亏自负。请确保充分了解期货交易风险,谨慎投资。 + +## 技术支持与更新 + +本系统仍在持续完善中,欢迎提供反馈和建议。使用过程中如遇问题,请提供以下信息: + +1. 系统运行环境(操作系统版本、Python版本) +2. 完整的错误信息和日志 +3. 问题发生时的操作步骤 + +## 版权声明 + +本策略代码版权归作者所有,仅供个人学习使用,禁止商业传播和销售。 \ No newline at end of file diff --git a/1.交易策略/999.其他策略/4.松鼠SF20_基于LLM的订单流日内交易策略/使用文档/3.28版本/专享策略20_基于LLM的订单流日内交易策略.py b/1.交易策略/999.其他策略/4.松鼠SF20_基于LLM的订单流日内交易策略/使用文档/3.28版本/专享策略20_基于LLM的订单流日内交易策略.py new file mode 100644 index 0000000..2a5f96c --- /dev/null +++ b/1.交易策略/999.其他策略/4.松鼠SF20_基于LLM的订单流日内交易策略/使用文档/3.28版本/专享策略20_基于LLM的订单流日内交易策略.py @@ -0,0 +1,2140 @@ +''' +#公众号:松鼠Quant +#主页:www.quant789.com +#本策略仅作学习交流使用,实盘交易盈亏投资者个人负责!!! +#版权归松鼠Quant所有,禁止转发、转卖源码违者必究。 + +该代码的主要目的是处理Tick数据并生成交易信号。代码中定义了一个tickcome函数,它接收到Tick数据后会进行一系列的处理,包括构建Tick字典、更新上一个Tick的成交量、保存Tick数据、生成K线数据等。其中涉及到的一些函数有: + +on_tick(tick): 处理单个Tick数据,根据Tick数据生成K线数据。 +tickdata(df, symbol): 处理Tick数据,生成K线数据。 +orderflow_df_new(df_tick, df_min, symbol): 处理Tick和K线数据,生成订单流数据。 +GetOrderFlow_dj(kData): 计算订单流的信号指标。 +除此之外,代码中还定义了一个MyTrader类,继承自TraderApiBase,用于实现交易相关的功能。 +#公众号:松鼠Quant +#主页:www.quant789.com +#本策略仅作学习交流使用,实盘交易盈亏投资者个人负责!!! +#版权归松鼠Quant所有,禁止转发、转卖源码违者必究。 +''' +from multiprocessing import Process, Queue +from AlgoPlus.CTP.MdApi import run_tick_engine +from AlgoPlus.CTP.FutureAccount import get_simulate_account +from AlgoPlus.CTP.FutureAccount import FutureAccount +from AlgoPlus.CTP.TraderApiBase import TraderApiBase +from AlgoPlus.ta.time_bar import tick_to_bar +import pandas as pd +from datetime import datetime +from datetime import time as s_time +import operator +import time +import numpy as np +import os +import re +import json +import requests # 添加requests库用于API调用 +from openai import OpenAI # 导入OpenAI客户端 +import threading +from queue import Queue as ThreadQueue +import warnings +warnings.filterwarnings("ignore", category=FutureWarning) + +# 在文件顶部定义全局变量 +tickdatadict = {} # 存储Tick数据的字典 +quotedict = {} # 存储行情数据的字典 +ofdatadict = {} # 存储K线数据的字典 +trader_df = pd.DataFrame({}) # 存储交易数据的DataFrame对象 +previous_volume = {} # 上一个Tick的成交量 +tsymbollist={} +# 全局LLM配置变量 +GLOBAL_LLM_CONFIG = {} # 全局大模型配置参数 +# 全局交易信号队列,用于存储AI模型生成的交易信号 +AI_SIGNAL_QUEUE = ThreadQueue() +# 标记是否有AI线程正在运行 +AI_THREAD_RUNNING = False +# K线时间粒度 +BAR_RESAMPLE_RULE = '1T' # 设置K线时间粒度,默认1分钟 + + +def tickcome(md_queue): + global previous_volume + + data=md_queue + instrument_id = data['InstrumentID'].decode() # 品种代码 + ActionDay = data['ActionDay'].decode() # 交易日日期 + update_time = data['UpdateTime'].decode() # 更新时间 + #zzg_quant + update_millisec = str(data['UpdateMillisec']) # 更新毫秒数 + created_at = ActionDay[:4] + '-' + ActionDay[4:6] + '-' + ActionDay[6:] + ' ' + update_time + '.' + update_millisec #创建时间 + # 构建tick字典 + tick = { + 'symbol': instrument_id, # 品种代码和交易所ID + 'created_at':datetime.strptime(created_at, "%Y-%m-%d %H:%M:%S.%f"), + #'created_at': created_at, # 创建时间 + 'price': float(data['LastPrice']), # 最新价 + 'last_volume': int(data['Volume']) - previous_volume.get(instrument_id, 0) if previous_volume.get(instrument_id, 0) != 0 else 0, # 瞬时成交量 + 'bid_p': float(data['BidPrice1']), # 买价 + 'bid_v': int(data['BidVolume1']), # 买量 + 'ask_p': float(data['AskPrice1']), # 卖价 + 'ask_v': int(data['AskVolume1']), # 卖量 + 'UpperLimitPrice': float(data['UpperLimitPrice']), # 涨停价 + 'LowerLimitPrice': float(data['LowerLimitPrice']), # 跌停价 + 'TradingDay': data['TradingDay'].decode(), # 交易日日期 + 'cum_volume': int(data['Volume']), # 最新总成交量 + 'cum_amount': float(data['Turnover']), # 最新总成交额 + 'cum_position': int(data['OpenInterest']), # 合约持仓量 + } + # 更新上一个Tick的成交量 + previous_volume[instrument_id] = int(data['Volume']) + if tick['last_volume']>0: + #print(tick['created_at'],'vol:',tick['last_volume']) + # 处理Tick数据 + on_tick(tick) + + +def can_time(hour, minute): + hour = str(hour) + minute = str(minute) + if len(minute) == 1: + minute = "0" + minute + return int(hour + minute) + +def on_tick(tick): + + tm=can_time(tick['created_at'].hour,tick['created_at'].minute) + #print(tick['symbol']) + #print(1) + #if tm>1500 and tm<2100 : + # return + if tick['last_volume']==0: + return + quotes = tick + timetick=str(tick['created_at']).replace('+08:00', '') + tsymbol=tick['symbol'] + if tsymbol not in tsymbollist.keys(): + # 获取tick的买卖价和买卖量 + #zzg_quant + tsymbollist[tsymbol]=tick + bid_p=quotes['bid_p'] + ask_p=quotes['ask_p'] + bid_v=quotes['bid_v'] + ask_v=quotes['ask_v'] + else: + # 获取上一个tick的买卖价和买卖量 + rquotes =tsymbollist[tsymbol] + bid_p=rquotes['bid_p'] + ask_p=rquotes['ask_p'] + bid_v=rquotes['bid_v'] + ask_v=rquotes['ask_v'] + tsymbollist[tsymbol]=tick + tick_dt=pd.DataFrame({'datetime':timetick,'symbol':tick['symbol'],'mainsym':tick['symbol'].rstrip('0123456789').upper(),'lastprice':tick['price'], + 'vol':tick['last_volume'], + 'bid_p':bid_p,'ask_p':ask_p,'bid_v':bid_v,'ask_v':ask_v},index=[0]) + sym = tick_dt['symbol'][0] + #print(tick_dt) + tickdata(tick_dt,sym) + +#公众号:松鼠Quant +#主页:www.quant789.com +#本策略仅作学习交流使用,实盘交易盈亏投资者个人负责!!! +#版权归松鼠Quant所有,禁止转发、转卖源码违者必究。 + +def data_of(df): + global trader_df + # 将df数据合并到trader_df中 + trader_df = pd.concat([trader_df, df], ignore_index=True) + #print('trader_df: ', len(trader_df)) + #print(trader_df) + +def process(bidDict, askDict, symbol): + try: + # 尝试从quotedict中获取对应品种的报价数据 + dic = quotedict[symbol] + bidDictResult = dic['bidDictResult'] + askDictResult = dic['askDictResult'] + except: + # 如果获取失败,则初始化bidDictResult和askDictResult为空字典 + bidDictResult, askDictResult = {}, {} + + # 将所有买盘字典和卖盘字典的key合并,并按升序排序 + sList = sorted(set(list(bidDict.keys()) + list(askDict.keys()))) + + # 遍历所有的key,将相同key的值进行累加 + for s in sList: + if s in bidDict: + if s in bidDictResult: + bidDictResult[s] = int(bidDict[s]) + bidDictResult[s] + else: + bidDictResult[s] = int(bidDict[s]) + if s not in askDictResult: + askDictResult[s] = 0 + else: + if s in askDictResult: + askDictResult[s] = int(askDict[s]) + askDictResult[s] + else: + askDictResult[s] = int(askDict[s]) + if s not in bidDictResult: + bidDictResult[s] = 0 + + # 构建包含bidDictResult和askDictResult的字典,并存入quotedict中 + df = {'bidDictResult': bidDictResult, 'askDictResult': askDictResult} + quotedict[symbol] = df + + return bidDictResult, askDictResult +#公众号:松鼠Quant +#主页:www.quant789.com +#本策略仅作学习交流使用,实盘交易盈亏投资者个人负责!!! +#版权归松鼠Quant所有,禁止转发、转卖源码违者必究。 + + +def tickdata(df,symbol): + tickdata =pd.DataFrame({'datetime':df['datetime'],'symbol':df['symbol'],'lastprice':df['lastprice'], + 'volume':df['vol'],'bid_p':df['bid_p'],'bid_v':df['bid_v'],'ask_p':df['ask_p'],'ask_v':df['ask_v']}) + try: + if symbol in tickdatadict.keys(): + rdf=tickdatadict[symbol] + rdftm=pd.to_datetime(rdf['bartime'][0]).strftime('%Y-%m-%d %H:%M:%S') + now=str(tickdata['datetime'][0]) + if now>rdftm: + try: + oo=ofdatadict[symbol] + data_of(oo) + #print('oo',oo) + if symbol in quotedict.keys(): + quotedict.pop(symbol) + if symbol in tickdatadict.keys(): + tickdatadict.pop(symbol) + if symbol in ofdatadict.keys(): + ofdatadict.pop(symbol) + except IOError as e: + print('rdftm捕获到异常',e) + tickdata['bartime'] = pd.to_datetime(tickdata['datetime']) + tickdata['open'] = tickdata['lastprice'] + tickdata['high'] = tickdata['lastprice'] + tickdata['low'] = tickdata['lastprice'] + tickdata['close'] = tickdata['lastprice'] + tickdata['starttime'] = tickdata['datetime'] + else: + tickdata['bartime'] = rdf['bartime'] + tickdata['open'] = rdf['open'] + tickdata['high'] = max(tickdata['lastprice'].values,rdf['high'].values) + tickdata['low'] = min(tickdata['lastprice'].values,rdf['low'].values) + tickdata['close'] = tickdata['lastprice'] + tickdata['volume']=df['vol']+rdf['volume'].values + tickdata['starttime'] = rdf['starttime'] + else : + print('新bar的第一个tick进入') + tickdata['bartime'] = pd.to_datetime(tickdata['datetime']) + tickdata['open'] = tickdata['lastprice'] + tickdata['high'] = tickdata['lastprice'] + tickdata['low'] = tickdata['lastprice'] + tickdata['close'] = tickdata['lastprice'] + tickdata['starttime'] = tickdata['datetime'] + except IOError as e: + print('捕获到异常',e) + + + tickdata['bartime'] = pd.to_datetime(tickdata['bartime']) + bardata = tickdata.resample(on = 'bartime', rule = BAR_RESAMPLE_RULE, label = 'right', closed = 'right').agg({'starttime':'first','symbol':'last','open':'first','high':'max','low':'min','close':'last','volume':'sum'}).reset_index(drop = False) + bardata =bardata.dropna().reset_index(drop = True) + bardata['bartime'] = pd.to_datetime(bardata['bartime'][0]).strftime('%Y-%m-%d %H:%M:%S') + tickdatadict[symbol]=bardata + tickdata['volume']=df['vol'].values + #print(bardata['symbol'].values,bardata['bartime'].values) + orderflow_df_new(tickdata,bardata,symbol) + # time.sleep(0.5) + +#公众号:松鼠Quant +#主页:www.quant789.com +#本策略仅作学习交流使用,实盘交易盈亏投资者个人负责!!! +#版权归松鼠Quant所有,禁止转发、转卖源码违者必究。 + +def orderflow_df_new(df_tick,df_min,symbol): + startArray = pd.to_datetime(df_min['starttime']).values + voluememin= df_min['volume'].values + highs=df_min['high'].values + lows=df_min['low'].values + opens=df_min['open'].values + closes=df_min['close'].values + #endArray = pd.to_datetime(df_min['bartime']).values + endArray = df_min['bartime'].values + #print(endArray) + deltaArray = np.zeros((len(endArray),)) + tTickArray = pd.to_datetime(df_tick['datetime']).values + bp1TickArray = df_tick['bid_p'].values + ap1TickArray = df_tick['ask_p'].values + lastTickArray = df_tick['lastprice'].values + volumeTickArray = df_tick['volume'].values + symbolarray = df_tick['symbol'].values + indexFinal = 0 + for index,tEnd in enumerate(endArray): + dt=endArray[index] + start = startArray[index] + bidDict = {} + askDict = {} + bar_vol=voluememin[index] + bar_close=closes[index] + bar_open=opens[index] + bar_low=lows[index] + bar_high=highs[index] + bar_symbol=symbolarray[index] + # for indexTick in range(indexFinal,len(df_tick)): + # if tTickArray[indexTick] >= tEnd: + # break + # elif (tTickArray[indexTick] >= start) & (tTickArray[indexTick] < tEnd): + Bp = round(bp1TickArray[0],4) + Ap = round(ap1TickArray[0],4) + LastPrice = round(lastTickArray[0],4) + Volume = volumeTickArray[0] + if LastPrice >= Ap: + if str(LastPrice) in askDict.keys(): + askDict[str(LastPrice)] += Volume + else: + askDict[str(LastPrice)] = Volume + if LastPrice <= Bp: + if str(LastPrice) in bidDict.keys(): + bidDict[str(LastPrice)] += Volume + else: + bidDict[str(LastPrice)] = Volume + # indexFinal = indexTick + bidDictResult,askDictResult = process(bidDict,askDict,symbol) + bidDictResult=dict(sorted(bidDictResult.items(),key=operator.itemgetter(0))) + askDictResult=dict(sorted(askDictResult.items(),key=operator.itemgetter(0))) + prinslist=list(bidDictResult.keys()) + asklist=list(askDictResult.values()) + bidlist=list(bidDictResult.values()) + delta=(sum(askDictResult.values()) - sum(bidDictResult.values())) + #print(prinslist,asklist,bidlist) + #print(len(prinslist),len(bidDictResult),len(askDictResult)) + df=pd.DataFrame({'price':pd.Series([prinslist]),'Ask':pd.Series([asklist]),'Bid':pd.Series([bidlist])}) + #df=pd.DataFrame({'price':pd.Series(bidDictResult.keys()),'Ask':pd.Series(askDictResult.values()),'Bid':pd.Series(bidDictResult.values())}) + df['symbol']=bar_symbol + df['datetime']=dt + df['delta']=str(delta) + df['close']=bar_close + df['open']=bar_open + df['high']=bar_high + df['low']=bar_low + df['volume']=bar_vol + #df['ticktime']=tTickArray[0] + df['dj'] = GetOrderFlow_dj(df) + ofdatadict[symbol]=df + +#公众号:松鼠Quant +#主页:www.quant789.com +#本策略仅作学习交流使用,实盘交易盈亏投资者个人负责!!! +#版权归松鼠Quant所有,禁止转发、转卖源码违者必究。 + +def GetOrderFlow_dj(kData): + Config = { + 'Value1': 3, + 'Value2': 3, + 'Value3': 3, + 'Value4': True, + } + aryData = kData + djcout = 0 + + # 遍历kData中的每一行,计算djcout指标 + for index, row in aryData.iterrows(): + kItem = aryData.iloc[index] + high = kItem['high'] + low = kItem['low'] + close = kItem['close'] + open = kItem['open'] + dtime = kItem['datetime'] + price_s = kItem['price'] + Ask_s = kItem['Ask'] + Bid_s = kItem['Bid'] + delta = kItem['delta'] + + price_s = price_s + Ask_s = Ask_s + Bid_s = Bid_s + + gj = 0 + xq = 0 + gxx = 0 + xxx = 0 + + # 遍历price_s中的每一个元素,计算相关指标 + for i in np.arange(0, len(price_s), 1): + duiji = { + 'price': 0, + 'time': 0, + 'longshort': 0, + } + + if i == 0: + delta = delta + + order= { + "Price":price_s[i], + "Bid":{ "Value":Bid_s[i]}, + "Ask":{ "Value":Ask_s[i]} + } + #空头堆积 + if i >= 0 and i < len(price_s) - 1: + if (order["Bid"]["Value"] > Ask_s[i + 1] * int(Config['Value1'])): + gxx += 1 + gj += 1 + if gj >= int(Config['Value2']) and Config['Value4'] == True: + duiji['price'] = price_s[i] + duiji['time'] = dtime + duiji['longshort'] = -1 + if float(duiji['price']) > 0: + djcout += -1 + else: + gj = 0 + #多头堆积 + if i >= 1 and i <= len(price_s) - 1: + if (order["Ask"]["Value"] > Bid_s[i - 1] * int(Config['Value1'])): + xq += 1 + xxx += 1 + if xq >= int(Config['Value2']) and Config['Value4'] == True: + duiji['price'] = price_s[i] + duiji['time'] = dtime + duiji['longshort'] = 1 + if float(duiji['price']) > 0: + djcout += 1 + else: + xq = 0 + + # 返回计算得到的djcout值 + return djcout + +#交易程序--------------------------------------------------------------------------------------------------------------------------------------------------------------------- + +class MyTrader(TraderApiBase): + def __init__(self, broker_id, td_server, investor_id, password, app_id, auth_code, md_queue=None, page_dir='', private_resume_type=2, public_resume_type=2): + # Cython类不使用super().__init__()方式调用父类初始化方法 + # TraderApiBase.__init__会由Cython自动处理 + + self.py=30 #设置委托价格的偏移,更加容易促成成交。仅螺纹,其他品种根据最小点波动,自己设置 + self.cont_df=0 + self.trailing_stop_percent = 0.005 #跟踪出场参数,从0.02减小到0.005 + self.fixed_stop_loss_percent = 0.01 #固定出场参数 + self.dj_X=1 #开仓的堆积参数 + + self.pos=0 + self.Lots=1 #下单手数 + self.short_trailing_stop_price = 0 + self.long_trailing_stop_price = 0 + self.sl_long_price=0 + self.sl_shor_price=0 + self.out_long=0 + self.out_short=0 + self.clearing_executed=False + self.day_closed = False # 添加日内平仓标志 + self.kgdata = True #历史数据加载一次 + self.holddata=True #持仓数据加载一次 + self.use_ai_model = True # 是否使用AI模型来分析 + + # 新增止盈止损字典,按合约ID索引 + self.stop_order_dict = {} + + # 新增历史数据加载相关参数 + self.load_history = False # 是否加载历史数据 + self.history_rows = 30 # 默认加载30行历史数据 + self.trader_rows = 10 # 当tader_df里的数据大于10行时开始计算指标及触发AI模型 + + def load_history_data(self, instrument_id): + """ + 加载历史数据 + + Args: + instrument_id: 合约ID + """ + if not self.load_history: + return + + try: + # 不再只提取英文字母,使用完整的合约代码 + symbol = str(instrument_id) + json_file_path = f"traderdata/{symbol}_ofdata.json" + + # 检查traderdata目录是否存在 + if not os.path.exists("traderdata"): + print(f"traderdata目录不存在,创建目录") + os.makedirs("traderdata") + + if os.path.exists(json_file_path): + try: + # 读取JSON文件,使用lines=True确保正确读取每行JSON + df = pd.read_json(json_file_path, lines=True) + + if len(df) == 0: + print(f"历史数据文件为空: {json_file_path}") + print("将使用实时数据开始交易") + return False + + # 如果数据行数超过设定的历史行数,只取最后N行 + if len(df) > self.history_rows: + df = df.tail(self.history_rows) + print(f"历史数据超过设定行数,仅加载最后{self.history_rows}行") + + # 更新全局trader_df + global trader_df + trader_df = df + + print(f"\n===== 历史数据加载成功 =====") + print(f"合约: {instrument_id}") + print(f"数据行数: {len(df)}行") + print(f"数据时间范围: {df['datetime'].iloc[0]} 到 {df['datetime'].iloc[-1]}") + print(f"最新价格: {df['close'].iloc[-1]}") + print(f"最新成交量: {df['volume'].iloc[-1]}") + print("===========================\n") + + # 更新cont_df + self.cont_df = len(df) + + # 计算日均线 + if len(df) > 0: + df['dayma'] = df['close'].mean() + + # 计算累积的delta值 + df['delta'] = df['delta'].astype(float) + df['delta累计'] = df['delta'].cumsum() + + return True + except Exception as e: + print(f"\n===== 历史数据加载错误 =====") + print(f"合约: {instrument_id}") + print(f"读取JSON错误: {e}") + print("将使用实时数据开始交易") + print("===========================\n") + return False + else: + print(f"\n===== 历史数据加载提示 =====") + print(f"合约: {instrument_id}") + print(f"未找到历史数据文件: {json_file_path}") + print("将使用实时数据开始交易") + print("===========================\n") + return False + + except Exception as e: + print(f"\n===== 历史数据加载错误 =====") + print(f"合约: {instrument_id}") + print(f"错误信息: {e}") + print("将使用实时数据开始交易") + print("===========================\n") + return False + + #读取保存的数据 + def read_to_csv(self,symbol): + # 文件夹路径和文件路径 + # 使用完整的合约代码 + symbol = str(symbol) + folder_path = "traderdata" + file_path = os.path.join(folder_path, f"{symbol}traderdata.csv") + # 如果文件夹不存在则创建 + if not os.path.exists(folder_path): + os.makedirs(folder_path) + + # 读取保留的模型数据CSV文件 + if os.path.exists(file_path): + df = pd.read_csv(file_path) + if not df.empty and self.holddata==True: + # 选择最后一行数据 + row = df.iloc[-1] + # 根据CSV文件的列名将数据赋值给相应的属性 + self.pos = int(row['pos']) + self.short_trailing_stop_price = float(row['short_trailing_stop_price']) + self.long_trailing_stop_price = float(row['long_trailing_stop_price']) + self.sl_long_price = float(row['sl_long_price']) + self.sl_shor_price = float(row['sl_shor_price']) + # self.out_long = int(row['out_long']) + # self.out_short = int(row['out_short']) + print("找到历史交易数据文件,已经更新持仓,止损止盈数据", df.iloc[-1]) + self.holddata=False + else: + pass + #print("没有找到历史交易数据文件", file_path) + #如果没有找到CSV,则初始化变量 + + pass + + #保存数据 + def save_to_csv(self,symbol): + # 使用完整的合约代码 + symbol = str(symbol) + # 创建DataFrame + data = { + 'datetime': [datetime.now().strftime('%Y-%m-%d %H:%M:%S')], # 使用当前时间 + 'pos': [self.pos], + 'short_trailing_stop_price': [self.short_trailing_stop_price], + 'long_trailing_stop_price': [self.long_trailing_stop_price], + 'sl_long_price': [self.sl_long_price], + 'sl_shor_price': [self.sl_shor_price], + } + + df = pd.DataFrame(data) + + # 将DataFrame保存到CSV文件 + df.to_csv(f"traderdata/{symbol}traderdata.csv", index=False) + + #每日收盘重置数据 + def day_data_reset(self,data): + # 获取当前时间 + current_time = datetime.now().time() + + # 第一时间范围 + clearing_time1_start = s_time(14,55) + clearing_time1_end = s_time(15,00) + + # 第二时间范围 + clearing_time2_start = s_time(2,25) + clearing_time2_end = s_time(2,30) + + current_bid = float(data['BidPrice1']) # 当前买价 + current_ask = float(data['AskPrice1']) # 当前卖价 + + # 创建一个标志变量,用于记录是否已经执行过 + self.clearing_executed = False + # 检查当前时间第一个操作的时间范围内 + if clearing_time1_start <= current_time <= clearing_time1_end and not self.clearing_executed : + self.clearing_executed = True # 设置标志变量为已执行 + + # 如果有持仓,强制平仓 + if self.pos != 0: + print("交易日结束,开始强制平仓") + # 遍历所有合约发送平仓指令 + for instrument_id in list(self.stop_order_dict.keys()): + stops = self.stop_order_dict[instrument_id] + + # 平多仓 + if stops['long']['position'] > 0: + print(f"发送平多仓指令: {instrument_id}, 手数: {stops['long']['position']}, 价格: {current_bid}") + self.insert_order(data['ExchangeID'], data['InstrumentID'], + current_bid - self.py, + stops['long']['position'], + b'1', b'3') + # 平空仓 + if stops['short']['position'] > 0: + print(f"发送平空仓指令: {instrument_id}, 手数: {stops['short']['position']}, 价格: {current_ask}") + self.insert_order(data['ExchangeID'], data['InstrumentID'], + current_ask + self.py, + stops['short']['position'], + b'0', b'3') + + # 清空所有合约的持仓信息 + for instrument_id in list(self.stop_order_dict.keys()): + self.clear_position_info(instrument_id, 'all') + self.day_closed = True # 设置日内平仓标志 + print("日内交易已结束,禁止开新仓") + + # 检查当前时间是否在第二个操作的时间范围内 + elif clearing_time2_start <= current_time <= clearing_time2_end and not self.clearing_executed : + self.clearing_executed = True # 设置标志变量为已执行 + + # 如果有持仓,强制平仓 + if self.pos != 0: + print("交易日结束,开始强制平仓") + # 遍历所有合约发送平仓指令 + for instrument_id in list(self.stop_order_dict.keys()): + stops = self.stop_order_dict[instrument_id] + + # 平多仓 + if stops['long']['position'] > 0: + print(f"发送平多仓指令: {instrument_id}, 手数: {stops['long']['position']}, 价格: {current_bid}") + self.insert_order(data['ExchangeID'], data['InstrumentID'], + current_bid - self.py, + stops['long']['position'], + b'1', b'3') + # 平空仓 + if stops['short']['position'] > 0: + print(f"发送平空仓指令: {instrument_id}, 手数: {stops['short']['position']}, 价格: {current_ask}") + self.insert_order(data['ExchangeID'], data['InstrumentID'], + current_ask + self.py, + stops['short']['position'], + b'0', b'3') + + # 清空所有合约的持仓信息 + for instrument_id in list(self.stop_order_dict.keys()): + self.clear_position_info(instrument_id, 'all') + self.day_closed = True # 设置日内平仓标志 + print("日内交易已结束,禁止开新仓") + else: + self.clearing_executed = False + # 在新交易日开始时重置日内平仓标志 + if current_time < clearing_time1_start or (current_time > clearing_time1_end and current_time < clearing_time2_start): + self.day_closed = False + return self.clearing_executed + + def OnRtnTrade(self, pTrade): + print("||成交回报||", pTrade) + + # 获取成交信息 + instrument_id = pTrade['InstrumentID'].decode() + direction = pTrade['Direction'].decode() # '0'为买入,'1'为卖出 + offset_flag = pTrade['OffsetFlag'].decode() # '0'为开仓,'1'为平仓,'3'为平今 + volume = pTrade['Volume'] + price = pTrade['Price'] + + # 根据成交类型更新持仓信息 + if offset_flag in ['1', '3']: # 平仓或平今 + # 判断平的是多头还是空头 + if direction == '1': # 卖出,平多头 + print(f"平多头成交: {instrument_id}, 价格: {price}, 数量: {volume}") + # 清空多头持仓信息 + self.clear_position_info(instrument_id, 'long') + else: # 买入,平空头 + print(f"平空头成交: {instrument_id}, 价格: {price}, 数量: {volume}") + # 清空空头持仓信息 + self.clear_position_info(instrument_id, 'short') + + elif offset_flag == '0': # 开仓 + if direction == '0': # 买入,开多头 + print(f"开多头成交: {instrument_id}, 价格: {price}, 数量: {volume}") + # 如果有空头持仓,先清空 + if instrument_id in self.stop_order_dict and self.stop_order_dict[instrument_id]['short']['position'] > 0: + self.clear_position_info(instrument_id, 'short') + + # 设置多头持仓信息 + sl_price = price * (1 - self.fixed_stop_loss_percent) # 默认止损价 + tp_price = price * (1 + self.trailing_stop_percent) # 默认止盈价 + + # 设置初始跟踪止损价,与开仓价保持一定距离 + initial_trailing_stop = price * (1 - self.trailing_stop_percent) + + print(f"设置止损价: {sl_price}, 止盈价: {tp_price}, 跟踪止损价: {initial_trailing_stop}, 跟踪百分比: {self.trailing_stop_percent*100:.3f}%") + + # 更新多头持仓信息,设置合理的跟踪止损初始值 + self.update_stop_order_dict(instrument_id, 'long', volume, price, sl_price, tp_price, initial_trailing_stop) + self.pos = volume # 更新全局持仓状态 + + # 兼容旧代码 + self.long_trailing_stop_price = initial_trailing_stop + self.sl_long_price = sl_price + self.save_to_csv(instrument_id) + + else: # 卖出,开空头 + print(f"开空头成交: {instrument_id}, 价格: {price}, 数量: {volume}") + # 如果有多头持仓,先清空 + if instrument_id in self.stop_order_dict and self.stop_order_dict[instrument_id]['long']['position'] > 0: + self.clear_position_info(instrument_id, 'long') + + # 设置空头持仓信息 + sl_price = price * (1 + self.fixed_stop_loss_percent) # 默认止损价 + tp_price = price * (1 - self.trailing_stop_percent) # 默认止盈价 + + # 设置初始跟踪止损价,与开仓价保持一定距离 + initial_trailing_stop = price * (1 + self.trailing_stop_percent) + + print(f"设置止损价: {sl_price}, 止盈价: {tp_price}, 跟踪止损价: {initial_trailing_stop}, 跟踪百分比: {self.trailing_stop_percent*100:.3f}%") + + # 更新空头持仓信息,设置合理的跟踪止损初始值 + self.update_stop_order_dict(instrument_id, 'short', self.Lots, price, sl_price, tp_price, initial_trailing_stop) + self.pos = -1 # 更新全局持仓状态 + + # 兼容旧代码 + self.short_trailing_stop_price = initial_trailing_stop + self.sl_shor_price = sl_price + self.save_to_csv(instrument_id) + + def OnRspOrderInsert(self, pInputOrder, pRspInfo, nRequestID, bIsLast): + print("||OnRspOrderInsert||", pInputOrder, pRspInfo, nRequestID, bIsLast) + + #公众号:松鼠Quant + #主页:www.quant789.com + #本策略仅作学习交流使用,实盘交易盈亏投资者个人负责!!! + #版权归松鼠Quant所有,禁止转发、转卖源码违者必究。 + + #注意:运行前请先安装好algoplus, + # pip install AlgoPlus + #http://www.algo.plus/ctp/python/0103001.html + + # 订单状态通知 + def OnRtnOrder(self, pOrder): + print("||订单回报||", pOrder) + + def Join(self): + data = None + # 记录上次加载止盈止损信息的时间和合约 + last_load_time = {} + + while True: + if self.status == 0: + + while not self.md_queue.empty(): + data = self.md_queue.get(block=False) + instrument_id = data['InstrumentID'].decode() # 品种代码 + + # 首次运行时加载历史数据 + if self.kgdata: + self.load_history_data(instrument_id) + self.kgdata = False + + # 加载该合约的止盈止损信息,避免频繁加载 + current_time = time.time() + if instrument_id not in last_load_time or current_time - last_load_time.get(instrument_id, 0) > 60: # 每60秒才重新加载一次 + self.load_stop_orders_from_file(instrument_id) + last_load_time[instrument_id] = current_time + + # 检查止盈止损条件 + self.check_stop_conditions(data) + + # 在每个tick都检查和处理AI交易信号 - 移到这里以提高执行速度 + if self.use_ai_model: + self.check_and_process_ai_signals(data) + + # 原有代码... + self.read_to_csv(instrument_id) + self.day_data_reset(data) + tickcome(data) + #新K线开始,启动交易程序 and 保存行情数据 + if len(trader_df)>self.cont_df and len(trader_df)>0: + # 计算日均线 + trader_df['dayma'] = trader_df['close'].mean() + + # 计算累积的delta值 + trader_df['delta'] = trader_df['delta'].astype(float) + trader_df['delta累计'] = trader_df['delta'].cumsum() + + # 检查文件是否存在 + json_file_path = f"traderdata/{instrument_id}_ofdata.json" + if os.path.exists(json_file_path): + try: + # 读取现有数据 + existing_df = pd.read_json(json_file_path, lines=True) + # 合并新数据 + combined_df = pd.concat([existing_df, trader_df.tail(1)], ignore_index=True) + # 保存合并后的数据,使用lines=True确保每行是独立的JSON对象 + combined_df.to_json(json_file_path, orient='records', force_ascii=False, lines=True) + except Exception as e: + print(f"读取或保存JSON文件时出错: {e}") + # 如果读取出错,直接保存当前数据 + trader_df.to_json(json_file_path, orient='records', force_ascii=False, lines=True) + else: + # 创建新文件并保存整个DataFrame + trader_df.to_json(json_file_path, orient='records', force_ascii=False, lines=True) + + # 更新跟踪止损价格 - 兼容旧版本代码 + if self.long_trailing_stop_price >0 and self.pos>0: + self.long_trailing_stop_price = trader_df['low'].iloc[-1] if self.long_trailing_stop_price0 and self.pos<0: + self.short_trailing_stop_price = trader_df['high'].iloc[-1] if trader_df['high'].iloc[-1] self.trader_rows: + AI_THREAD_RUNNING = True + ai_thread = threading.Thread( + target=self.background_model_call, + args=(trader_df, instrument_id) + ) + ai_thread.daemon = True # 设置为守护线程,主程序退出时自动结束 + ai_thread.start() + print("启动AI分析线程...") + + print(trader_df) + self.cont_df=len(trader_df) + else: + time.sleep(1) + + def background_model_call(self, data_df, instrument_id): + """ + 在后台线程中调用大模型,并将交易信号放入队列 + + Args: + data_df: 包含订单流数据的DataFrame + instrument_id: 合约ID + """ + global AI_THREAD_RUNNING + + start_time = datetime.now() + print(f"\n===== 开始AI分析 [{start_time.strftime('%H:%M:%S')}] =====") + print(f"正在分析合约: {instrument_id}") + + try: + # 复制DataFrame以避免在不同线程间共享数据可能导致的问题 + df_copy = data_df.copy() + + # 输出分析的数据行数 + print(f"分析数据行数: {len(df_copy)}") + print(f"最新价格: {df_copy['close'].iloc[-1] if len(df_copy) > 0 else 'N/A'}") + + # 调用大模型获取交易信号 + trading_signal = call_deepseek_model(df_copy, self) # 传递self参数 + + # 计算分析耗时 + end_time = datetime.now() + elapsed = (end_time - start_time).total_seconds() + + # 将交易信号和合约ID一起放入队列 + signal_data = { + 'signal': trading_signal, + 'instrument_id': instrument_id, + 'timestamp': end_time # 使用结束时间作为时间戳 + } + + AI_SIGNAL_QUEUE.put(signal_data) + print(f"AI模型分析完成,结果已放入队列,耗时: {elapsed:.2f}秒") + print(f"分析结果: {trading_signal}") + print("===== AI分析完成 =====\n") + except Exception as e: + end_time = datetime.now() + elapsed = (end_time - start_time).total_seconds() + print(f"AI模型分析线程出现异常: {e}") + print(f"异常详情:") + import traceback + traceback.print_exc() + print(f"分析失败,耗时: {elapsed:.2f}秒") + print("===== AI分析异常结束 =====\n") + finally: + # 标记线程已完成 + AI_THREAD_RUNNING = False + + + #公众号:松鼠Quant + #主页:www.quant789.com + #本策略仅作学习交流使用,实盘交易盈亏投资者个人负责!!! + #版权归松鼠Quant所有,禁止转发、转卖源码违者必究。 + + #注意:运行前请先安装好algoplus, + # pip install AlgoPlus + #http://www.algo.plus/ctp/python/0103001.html + + def check_and_process_ai_signals(self, data): + """ + 检查并处理AI产生的交易信号 + 每个tick都会调用此函数,实现更快的交易信号响应 + """ + if AI_SIGNAL_QUEUE.empty(): + return + + # 从队列中获取信号 + signal_data = AI_SIGNAL_QUEUE.get() + trading_signal = signal_data['signal'] + instrument_id = signal_data['instrument_id'] + signal_time = signal_data['timestamp'] + + # 检查信号是否过期(超过15秒) + if (datetime.now() - signal_time).total_seconds() > 15: + print(f"AI信号已过期,忽略: {trading_signal}") + return + + # 验证合约ID是否匹配 + if instrument_id != data['InstrumentID'].decode(): + # 如果合约不匹配,将信号放回队列以便后续处理 + AI_SIGNAL_QUEUE.put(signal_data) + return + + print(f"\n===== 执行AI模型交易信号 [{datetime.now().strftime('%H:%M:%S')}] =====") + print(f"信号生成时间: {signal_time.strftime('%H:%M:%S')}") + print(f"信号类型: {trading_signal.get('action', '不操作')}") + print(f"置信度: {trading_signal.get('confidence', 0)}") + print(f"理由: {trading_signal.get('reason', '')}") + + # 根据AI模型返回的交易信号执行交易 + action = trading_signal.get('action', '不操作') + confidence = trading_signal.get('confidence', 0) + reason = trading_signal.get('reason', '') + stop_loss = trading_signal.get('stop_loss', 0) + take_profit = trading_signal.get('take_profit', 0) + trailing_percent = trading_signal.get('trailing_percent', 0) + + # 如果AI建议了有效的跟踪止损百分比,则更新参数 + if 0.0001 <= trailing_percent <= 0.001: + old_percent = self.trailing_stop_percent + self.trailing_stop_percent = trailing_percent + print(f"更新跟踪止损百分比参数: {old_percent*100:.3f}% -> {trailing_percent*100:.3f}%") + + # 获取现有持仓信息 + if instrument_id not in self.stop_order_dict: + self.stop_order_dict[instrument_id] = { + 'long': {'position': 0, 'entry_price': 0, 'stop_loss': 0, 'take_profit': 0, 'trailing_stop': 0}, + 'short': {'position': 0, 'entry_price': 0, 'stop_loss': 0, 'take_profit': 0, 'trailing_stop': 0} + } + + current_stops = self.stop_order_dict[instrument_id] + + # 如果持有多头或空头头寸,更新跟踪止损价 + if current_stops['long']['position'] > 0: + entry_price = current_stops['long']['entry_price'] + new_trailing_stop = float(data['BidPrice1']) * (1 - self.trailing_stop_percent) + old_trailing_stop = current_stops['long']['trailing_stop'] + + # 只有当新计算的跟踪止损价更高时才更新 + if new_trailing_stop > old_trailing_stop: + self.update_stop_order_dict(instrument_id, 'long', None, None, None, None, new_trailing_stop) + print(f"已根据新参数更新多头跟踪止损价: {old_trailing_stop} -> {new_trailing_stop}") + + # 兼容旧代码 + self.long_trailing_stop_price = new_trailing_stop + self.save_to_csv(instrument_id) + + elif current_stops['short']['position'] > 0: + entry_price = current_stops['short']['entry_price'] + new_trailing_stop = float(data['AskPrice1']) * (1 + self.trailing_stop_percent) + old_trailing_stop = current_stops['short']['trailing_stop'] + + # 只有当新计算的跟踪止损价更低时才更新 + if new_trailing_stop < old_trailing_stop or old_trailing_stop == 0: + self.update_stop_order_dict(instrument_id, 'short', None, None, None, None, new_trailing_stop) + print(f"已根据新参数更新空头跟踪止损价: {old_trailing_stop} -> {new_trailing_stop}") + + # 兼容旧代码 + self.short_trailing_stop_price = new_trailing_stop + self.save_to_csv(instrument_id) + + # 只有当置信度大于等于5时才执行交易 + if confidence >= 6: + print(f"开始执行交易,当前价格: 买一{data['BidPrice1']} / 卖一{data['AskPrice1']}") + + # 获取现有持仓信息 + if instrument_id not in self.stop_order_dict: + self.stop_order_dict[instrument_id] = { + 'long': {'position': 0, 'entry_price': 0, 'stop_loss': 0, 'take_profit': 0, 'trailing_stop': 0}, + 'short': {'position': 0, 'entry_price': 0, 'stop_loss': 0, 'take_profit': 0, 'trailing_stop': 0} + } + + current_stops = self.stop_order_dict[instrument_id] + + if action == '开多' and current_stops['long']['position'] <= 0: + # 如果持有空头头寸,先平空 + if current_stops['short']['position'] > 0: + print('执行平空操作') + self.insert_order(data['ExchangeID'], data['InstrumentID'], + data['AskPrice1']+self.py, + current_stops['short']['position'], + b'0', b'3') + # 清空空头持仓信息 + self.clear_position_info(instrument_id, 'short') + + # 开多 + print('执行开多操作') + entry_price = float(data['AskPrice1']) + self.insert_order(data['ExchangeID'], data['InstrumentID'], + entry_price+self.py, self.Lots, b'0', b'0') + + # 使用AI建议的止损止盈价格 + sl_price = stop_loss if stop_loss > 0 else entry_price * (1 - self.fixed_stop_loss_percent) + tp_price = take_profit if take_profit > 0 else entry_price * (1 + self.trailing_stop_percent) + + # 设置初始跟踪止损价,与开仓价保持一定距离 + initial_trailing_stop = entry_price * (1 - self.trailing_stop_percent) + + print(f"设置止损价: {sl_price}, 止盈价: {tp_price}, 跟踪止损价: {initial_trailing_stop}, 跟踪百分比: {self.trailing_stop_percent*100:.3f}%") + + # 更新多头持仓信息,设置合理的跟踪止损初始值 + self.update_stop_order_dict(instrument_id, 'long', self.Lots, entry_price, sl_price, tp_price, initial_trailing_stop) + self.pos = 1 # 更新全局持仓状态 + + # 兼容旧代码 + self.long_trailing_stop_price = initial_trailing_stop + self.sl_long_price = sl_price + self.save_to_csv(instrument_id) + + elif action == '开空' and current_stops['short']['position'] <= 0: + # 如果持有多头头寸,先平多 + if current_stops['long']['position'] > 0: + print('执行平多操作') + self.insert_order(data['ExchangeID'], data['InstrumentID'], + data['BidPrice1']-self.py, + current_stops['long']['position'], + b'1', b'3') + # 清空多头持仓信息 + self.clear_position_info(instrument_id, 'long') + + # 开空 + print('执行开空操作') + entry_price = float(data['BidPrice1']) + self.insert_order(data['ExchangeID'], data['InstrumentID'], + entry_price-self.py, self.Lots, b'1', b'0') + + # 使用AI建议的止损止盈价格 + sl_price = stop_loss if stop_loss > 0 else entry_price * (1 + self.fixed_stop_loss_percent) + tp_price = take_profit if take_profit > 0 else entry_price * (1 - self.trailing_stop_percent) + + # 设置初始跟踪止损价,与开仓价保持一定距离 + initial_trailing_stop = entry_price * (1 + self.trailing_stop_percent) + + print(f"设置止损价: {sl_price}, 止盈价: {tp_price}, 跟踪止损价: {initial_trailing_stop}, 跟踪百分比: {self.trailing_stop_percent*100:.3f}%") + + # 更新空头持仓信息,设置合理的跟踪止损初始值 + self.update_stop_order_dict(instrument_id, 'short', self.Lots, entry_price, sl_price, tp_price, initial_trailing_stop) + self.pos = -1 # 更新全局持仓状态 + + # 兼容旧代码 + self.short_trailing_stop_price = initial_trailing_stop + self.sl_shor_price = sl_price + self.save_to_csv(instrument_id) + + elif action == '平多' and current_stops['long']['position'] > 0: + print('执行平多操作') + self.insert_order(data['ExchangeID'], data['InstrumentID'], + data['BidPrice1']-self.py, + current_stops['long']['position'], + b'1', b'3') + # 清空多头持仓信息 + self.clear_position_info(instrument_id, 'long') + + elif action == '平空' and current_stops['short']['position'] > 0: + print('执行平空操作') + self.insert_order(data['ExchangeID'], data['InstrumentID'], + data['AskPrice1']+self.py, + current_stops['short']['position'], + b'0', b'3') + # 清空空头持仓信息 + self.clear_position_info(instrument_id, 'short') + + # 如果AI建议调整止损止盈价格 + elif action == '不操作': + if stop_loss > 0: + if current_stops['long']['position'] > 0: # 多头持仓 + self.update_stop_order_dict(instrument_id, 'long', None, None, stop_loss, None, None) + print(f'已调整多头止损价: {stop_loss}') + + # 兼容旧代码 + self.sl_long_price = stop_loss + self.save_to_csv(instrument_id) + elif current_stops['short']['position'] > 0: # 空头持仓 + self.update_stop_order_dict(instrument_id, 'short', None, None, stop_loss, None, None) + print(f'已调整空头止损价: {stop_loss}') + + # 兼容旧代码 + self.sl_shor_price = stop_loss + self.save_to_csv(instrument_id) + + if take_profit > 0: + if current_stops['long']['position'] > 0: # 多头持仓 + self.update_stop_order_dict(instrument_id, 'long', None, None, None, take_profit, None) + print(f'已调整多头止盈价: {take_profit}') + + # 兼容旧代码 + self.long_trailing_stop_price = take_profit + self.save_to_csv(instrument_id) + elif current_stops['short']['position'] > 0: # 空头持仓 + self.update_stop_order_dict(instrument_id, 'short', None, None, None, take_profit, None) + print(f'已调整空头止盈价: {take_profit}') + + # 兼容旧代码 + self.short_trailing_stop_price = take_profit + self.save_to_csv(instrument_id) + + print("===== 交易信号执行完成 =====\n") + else: + print(f"信号置信度{confidence}低于执行阈值(5),不执行交易") + print("===== 交易信号处理完成 =====\n") + + #公众号:松鼠Quant + #主页:www.quant789.com + #本策略仅作学习交流使用,实盘交易盈亏投资者个人负责!!! + #版权归松鼠Quant所有,禁止转发、转卖源码违者必究。 + + #注意:运行前请先安装好algoplus, + # pip install AlgoPlus + #http://www.algo.plus/ctp/python/0103001.html + + def format_data_for_llm(self, df): + """ + 将DataFrame格式化为适合LLM分析的文本格式,包含历史交易信息 + """ + # 提取最近几条记录 + recent_data = df.tail(self.trader_rows) + + # 构建基本信息 + data_text = "订单流数据分析:\n\n" + + # 提取最新行情数据 + instrument_id = recent_data['symbol'].iloc[-1] + + # 添加最新价格和交易量信息 + data_text += f"当前时间: {recent_data['datetime'].iloc[-1]}\n" + data_text += f"当前价格: {recent_data['close'].iloc[-1]}\n" + data_text += f"开盘价: {recent_data['open'].iloc[-1]}\n" + data_text += f"最高价: {recent_data['high'].iloc[-1]}\n" + data_text += f"最低价: {recent_data['low'].iloc[-1]}\n" + data_text += f"成交量: {recent_data['volume'].iloc[-1]}\n" + + # 计算价格趋势 + if len(recent_data) >= 5: + price_trend = recent_data['close'].pct_change().tail(5).mean() * 100 + data_text += f"价格短期趋势: {'上涨' if price_trend > 0 else '下跌'} ({price_trend:.2f}%)\n" + + # 计算价格波动性 + if len(recent_data) >= 5: + volatility = recent_data['close'].pct_change().tail(5).std() * 100 + data_text += f"价格波动性: {volatility:.2f}%\n" + + # 添加支撑和阻力位分析 + recent_high = recent_data['high'].max() + recent_low = recent_data['low'].min() + data_text += f"近期阻力位: {recent_high}\n" + data_text += f"近期支撑位: {recent_low}\n" + + # 添加均线分析 - 计算5、10、20均线 + if len(df) >= 20: + # 计算均线 + ma5 = df['close'].rolling(5).mean().iloc[-1] + ma10 = df['close'].rolling(10).mean().iloc[-1] + ma20 = df['close'].rolling(20).mean().iloc[-1] + + data_text += f"MA5: {ma5:.2f}\n" + data_text += f"MA10: {ma10:.2f}\n" + data_text += f"MA20: {ma20:.2f}\n" + + # 判断均线形态 + if abs(ma5 - ma10) / ma10 < 0.001 and abs(ma10 - ma20) / ma20 < 0.001: + ma_pattern = "均线粘合" + elif ma5 > ma10 and ma10 > ma20: + ma_pattern = "多头排列" + elif ma5 < ma10 and ma10 < ma20: + ma_pattern = "空头排列" + elif ma5 > ma10 and ma10 < ma20: + ma_pattern = "金叉形态" + elif ma5 < ma10 and ma10 > ma20: + ma_pattern = "死叉形态" + else: + ma_pattern = "无明显形态" + + data_text += f"均线形态: {ma_pattern}\n" + + # 价格与均线关系 + current_price = df['close'].iloc[-1] + data_text += f"价格相对MA5: {'上方' if current_price > ma5 else '下方'} ({(current_price/ma5-1)*100:.2f}%)\n" + data_text += f"价格相对MA10: {'上方' if current_price > ma10 else '下方'} ({(current_price/ma10-1)*100:.2f}%)\n" + data_text += f"价格相对MA20: {'上方' if current_price > ma20 else '下方'} ({(current_price/ma20-1)*100:.2f}%)\n" + + # 日内超涨超跌分析 + if len(df) >= 20: + # 计算日内振幅 + daily_high = df['high'].iloc[-20:].max() + daily_low = df['low'].iloc[-20:].min() + daily_range = (daily_high - daily_low) / daily_low * 100 + + # 当前价格在日内范围的位置 + current_in_range = (df['close'].iloc[-1] - daily_low) / (daily_high - daily_low) * 100 if (daily_high - daily_low) > 0 else 50 + + data_text += f"日内振幅: {daily_range:.2f}%\n" + data_text += f"价格在日内范围的位置: {current_in_range:.2f}% (0%为日低, 100%为日高)\n" + + # 判断超涨超跌 + if current_in_range > 85: + data_text += "日内状态: 可能超涨\n" + elif current_in_range < 15: + data_text += "日内状态: 可能超跌\n" + else: + data_text += "日内状态: 正常区间\n" + + # 形态识别 + if len(df) >= 20: + # 简单K线形态识别 + recent_k = df.tail(5).copy() + + # 计算实体和影线 + recent_k['body'] = abs(recent_k['close'] - recent_k['open']) + recent_k['upper_shadow'] = recent_k.apply(lambda x: x['high'] - max(x['open'], x['close']), axis=1) + recent_k['lower_shadow'] = recent_k.apply(lambda x: min(x['open'], x['close']) - x['low'], axis=1) + + # 最新K线特征 + latest_k = recent_k.iloc[-1] + prev_k = recent_k.iloc[-2] if len(recent_k) > 1 else None + + data_text += "\nK线形态分析:\n" + + # 判断最新K线类型 + if latest_k['body'] == 0: + k_type = "十字星" + elif latest_k['upper_shadow'] > 2 * latest_k['body'] and latest_k['lower_shadow'] < 0.5 * latest_k['body']: + k_type = "上影线长" + elif latest_k['lower_shadow'] > 2 * latest_k['body'] and latest_k['upper_shadow'] < 0.5 * latest_k['body']: + k_type = "下影线长" + elif latest_k['close'] > latest_k['open'] and latest_k['body'] > np.mean(recent_k['body']): + k_type = "大阳线" + elif latest_k['close'] < latest_k['open'] and latest_k['body'] > np.mean(recent_k['body']): + k_type = "大阴线" + elif latest_k['close'] > latest_k['open']: + k_type = "小阳线" + elif latest_k['close'] < latest_k['open']: + k_type = "小阴线" + else: + k_type = "普通K线" + + data_text += f"最新K线类型: {k_type}\n" + + # 判断简单组合形态 + if prev_k is not None: + if prev_k['close'] < prev_k['open'] and latest_k['close'] > latest_k['open'] and latest_k['open'] <= prev_k['close'] and latest_k['close'] > prev_k['open']: + data_text += "组合形态: 可能构成看涨吞没形态\n" + elif prev_k['close'] > prev_k['open'] and latest_k['close'] < latest_k['open'] and latest_k['open'] >= prev_k['close'] and latest_k['close'] < prev_k['open']: + data_text += "组合形态: 可能构成看跌吞没形态\n" + elif prev_k['close'] < prev_k['open'] and latest_k['close'] > latest_k['open'] and latest_k['body'] > 1.5 * prev_k['body']: + data_text += "组合形态: 可能构成看涨势能增强\n" + elif prev_k['close'] > prev_k['open'] and latest_k['close'] < latest_k['open'] and latest_k['body'] > 1.5 * prev_k['body']: + data_text += "组合形态: 可能构成看跌势能增强\n" + + # 添加订单流特定数据 + data_text += f"\n订单流净值: {recent_data['delta'].iloc[-1]}\n" + data_text += f"订单流累计值: {recent_data['delta累计'].iloc[-1] if 'delta累计' in recent_data.columns else '无数据'}\n" + data_text += f"堆积指标: {recent_data['dj'].iloc[-1]}\n" + + # 添加日均线数据 + data_text += f"日均线: {recent_data['dayma'].iloc[-1] if 'dayma' in recent_data.columns else '无数据'}\n" + + # 添加价格与日均线的关系 + if 'dayma' in recent_data.columns: + price_above_ma = recent_data['close'].iloc[-1] > recent_data['dayma'].iloc[-1] + data_text += f"价格位于日均线: {'上方' if price_above_ma else '下方'}\n" + + # 订单流全面分析 + data_text += "\n订单流详细分析:\n" + + # 计算订单流趋势 + if len(recent_data) >= 5: + delta_values = recent_data['delta'].values + delta_trend = np.mean(np.diff(delta_values)) if len(delta_values) > 1 else 0 + data_text += f"订单流趋势: {'增强中' if delta_trend > 0 else '减弱中'} (变化率: {delta_trend:.2f})\n" + + # 计算订单流强度(使用绝对值的平均值) + delta_strength = np.mean(np.abs(recent_data['delta'].values)) + data_text += f"订单流强度: {delta_strength:.2f}\n" + + # 订单流指标超涨超跌分析 + if len(df) >= 20: + delta_values = df['delta'].iloc[-20:].values + delta_mean = np.mean(delta_values) + delta_std = np.std(delta_values) + current_delta = df['delta'].iloc[-1] + + # Z分数计算 + if delta_std > 0: + delta_z = (current_delta - delta_mean) / delta_std + data_text += f"订单流偏离度(Z分数): {delta_z:.2f}\n" + + if delta_z > 2: + data_text += "订单流状态: 可能超买\n" + elif delta_z < -2: + data_text += "订单流状态: 可能超卖\n" + else: + data_text += "订单流状态: 正常区间\n" + + # 买卖力量对比 + if 'bid_v' in recent_data.columns and 'ask_v' in recent_data.columns: + bid_power = recent_data['bid_v'].mean() + ask_power = recent_data['ask_v'].mean() + power_ratio = bid_power / ask_power if ask_power != 0 else float('inf') + data_text += f"买卖比例: {power_ratio:.2f} (>1买方强势,<1卖方强势)\n" + + # 订单流累计趋势 + if 'delta累计' in recent_data.columns and len(recent_data) >= 2: + cumulative_start = recent_data['delta累计'].iloc[0] + cumulative_end = recent_data['delta累计'].iloc[-1] + cumulative_change = cumulative_end - cumulative_start + data_text += f"累计订单流变化: {cumulative_change:.2f} (从 {cumulative_start:.2f} 到 {cumulative_end:.2f})\n" + + # 订单流波动性 + delta_volatility = np.std(recent_data['delta'].values) + data_text += f"订单流波动性: {delta_volatility:.2f}\n" + + # 订单流与价格相关性 + if len(recent_data) >= 10: # 确保有足够数据计算相关性 + price_changes = recent_data['close'].pct_change().dropna() + delta_changes = recent_data['delta'].iloc[1:].reset_index(drop=True) # 对齐索引 + if len(price_changes) > 0 and len(delta_changes) == len(price_changes): + try: + correlation = np.corrcoef(price_changes, delta_changes)[0, 1] if len(price_changes) > 1 else 0 + data_text += f"订单流与价格相关性: {correlation:.2f}\n" + data_text += f"相关性解读: {'强正相关' if correlation > 0.7 else '正相关' if correlation > 0.3 else '弱相关' if correlation > -0.3 else '负相关' if correlation > -0.7 else '强负相关'}\n" + except: + data_text += "订单流与价格相关性: 计算错误\n" + + # 订单流势能分析(最近几分钟的方向) + recent_deltas = recent_data['delta'].tail(5).values + positive_count = sum(1 for x in recent_deltas if x > 0) + negative_count = sum(1 for x in recent_deltas if x < 0) + data_text += f"最近订单流方向: {'多头主导' if positive_count > negative_count else '空头主导' if positive_count < negative_count else '方向不明'} ({positive_count}正/{negative_count}负)\n" + + # 订单流强弱可视化 + delta_last_5 = recent_data['delta'].tail(5).values + strength_visual = "" + for val in delta_last_5: + if val > 3: + strength_visual += "↑↑ " + elif val > 0: + strength_visual += "↑ " + elif val < -3: + strength_visual += "↓↓ " + elif val < 0: + strength_visual += "↓ " + else: + strength_visual += "→ " + data_text += f"订单流强弱可视化 (最近5分钟): {strength_visual}\n" + + # 添加最近几条记录的趋势 + data_text += "\n最近几条记录的趋势:\n" + + # 添加最近5条记录的关键指标变化 + for i in range(min(5, len(recent_data))): + idx = -(i+1) + data_text += f"记录 {i+1}: 时间={recent_data['datetime'].iloc[idx]}, 价格={recent_data['close'].iloc[idx]}, " + data_text += f"订单流净值={recent_data['delta'].iloc[idx]}, 堆积={recent_data['dj'].iloc[idx]}\n" + + # 添加当前持仓信息,使用新的止盈止损字典 + data_text += "\n当前持仓状态:\n" + + # 获取该合约的止盈止损信息 + stops = self.stop_order_dict.get(instrument_id, { + 'long': {'position': 0, 'entry_price': 0, 'stop_loss': 0, 'take_profit': 0, 'trailing_stop': 0}, + 'short': {'position': 0, 'entry_price': 0, 'stop_loss': 0, 'take_profit': 0, 'trailing_stop': 0} + }) + + # 获取多头和空头持仓信息 + long_pos = stops.get('long', {}).get('position', 0) + short_pos = stops.get('short', {}).get('position', 0) + + # 判断当前持仓方向 + if long_pos > 0: + data_text += f"持仓方向: 多头\n" + data_text += f"持仓数量: {long_pos}\n" + data_text += f"开仓价格: {stops['long']['entry_price']}\n" + data_text += f"止损价格: {stops['long']['stop_loss']}\n" + data_text += f"止盈价格: {stops['long']['take_profit']}\n" + data_text += f"跟踪止损价: {stops['long']['trailing_stop']}\n" + + # 计算当前盈亏 + current_price = recent_data['close'].iloc[-1] + profit_percent = (current_price - stops['long']['entry_price']) / stops['long']['entry_price'] * 100 + data_text += f"当前盈亏: {profit_percent:.2f}%\n" + elif short_pos > 0: + data_text += f"持仓方向: 空头\n" + data_text += f"持仓数量: {short_pos}\n" + data_text += f"开仓价格: {stops['short']['entry_price']}\n" + data_text += f"止损价格: {stops['short']['stop_loss']}\n" + data_text += f"止盈价格: {stops['short']['take_profit']}\n" + data_text += f"跟踪止损价: {stops['short']['trailing_stop']}\n" + + # 计算当前盈亏 + current_price = recent_data['close'].iloc[-1] + profit_percent = (stops['short']['entry_price'] - current_price) / stops['short']['entry_price'] * 100 + data_text += f"当前盈亏: {profit_percent:.2f}%\n" + else: + data_text += "持仓方向: 空仓\n" + data_text += "持仓数量: 0\n" + + # 添加风险管理参数信息 + data_text += "\n风险管理参数设置:\n" + data_text += f"固定止损百分比: {self.fixed_stop_loss_percent * 100:.2f}%\n" + data_text += f"跟踪止损百分比: {self.trailing_stop_percent * 100:.2f}%\n" + + # 添加交易建议提示 + data_text += "\n请根据以上信息,分析当前市场状态并给出交易建议。需要考虑:\n" + data_text += "1. 当前持仓状态是否合理\n" + data_text += "2. 是否需要调整止损止盈位置\n" + data_text += "3. 是否需要平仓或反手\n" + data_text += "4. 是否适合开新仓\n" + data_text += "5. 是否需要调整跟踪止损百分比参数(范围建议:0.0001-0.001)\n" + data_text += "6. 是否出现抄底摸顶机会\n" + data_text += "7. 是否存在日内波段交易机会\n" + + return data_text + + def update_stop_order_dict(self, instrument_id, direction, position, entry_price=None, stop_loss=None, take_profit=None, trailing_stop=None): + """ + 更新止盈止损字典 + + Args: + instrument_id: 合约ID + direction: 方向 'long' 或 'short' + position: 持仓手数 + entry_price: 开仓价格 + stop_loss: 止损价格 + take_profit: 止盈价格 + trailing_stop: 跟踪止损价格 + """ + # 确保合约ID在字典中存在 + if instrument_id not in self.stop_order_dict: + self.stop_order_dict[instrument_id] = { + 'long': {'position': 0, 'entry_price': 0, 'stop_loss': 0, 'take_profit': 0, 'trailing_stop': 0}, + 'short': {'position': 0, 'entry_price': 0, 'stop_loss': 0, 'take_profit': 0, 'trailing_stop': 0} + } + + # 更新指定方向的数据,仅更新提供的参数 + if position is not None: + self.stop_order_dict[instrument_id][direction]['position'] = position + + if entry_price is not None: + self.stop_order_dict[instrument_id][direction]['entry_price'] = entry_price + + if stop_loss is not None: + self.stop_order_dict[instrument_id][direction]['stop_loss'] = stop_loss + + if take_profit is not None: + self.stop_order_dict[instrument_id][direction]['take_profit'] = take_profit + + if trailing_stop is not None: + self.stop_order_dict[instrument_id][direction]['trailing_stop'] = trailing_stop + + # 保存到文件 + self.save_stop_orders_to_file(instrument_id) + + def save_stop_orders_to_file(self, instrument_id): + """将止盈止损信息保存到文件""" + # 使用完整的合约代码 + symbol = str(instrument_id) + folder_path = "traderdata" + file_path = os.path.join(folder_path, f"{symbol}_stops.json") + + # 如果文件夹不存在则创建 + if not os.path.exists(folder_path): + os.makedirs(folder_path) + + # 保存字典到JSON文件 + with open(file_path, 'w') as f: + json.dump(self.stop_order_dict.get(instrument_id, {}), f, indent=4) + + # 获取该合约的止盈止损信息 + stops = self.stop_order_dict.get(instrument_id, { + 'long': {'position': 0, 'entry_price': 0, 'stop_loss': 0, 'take_profit': 0, 'trailing_stop': 0}, + 'short': {'position': 0, 'entry_price': 0, 'stop_loss': 0, 'take_profit': 0, 'trailing_stop': 0} + }) + + # 打印详细信息 + print(f"\n===== 已更新止盈止损信息: {instrument_id} =====") + print(f"多头持仓: {stops['long']['position']} 手") + print(f"多头入场价: {stops['long']['entry_price']}") + print(f"多头止损价: {stops['long']['stop_loss']}") + print(f"多头止盈价: {stops['long']['take_profit']}") + print(f"多头跟踪止损: {stops['long']['trailing_stop']}") + print(f"空头持仓: {stops['short']['position']} 手") + print(f"空头入场价: {stops['short']['entry_price']}") + print(f"空头止损价: {stops['short']['stop_loss']}") + print(f"空头止盈价: {stops['short']['take_profit']}") + print(f"空头跟踪止损: {stops['short']['trailing_stop']}") + print("======================================\n") + + def load_stop_orders_from_file(self, instrument_id): + """从文件加载止盈止损信息""" + # 如果合约ID已经在字典中,直接返回,避免重复加载 + if instrument_id in self.stop_order_dict: + return True + + # 使用完整的合约代码 + symbol = str(instrument_id) + folder_path = "traderdata" + file_path = os.path.join(folder_path, f"{symbol}_stops.json") + + if os.path.exists(file_path): + try: + with open(file_path, 'r') as f: + stops_data = json.load(f) + + # 更新字典 + self.stop_order_dict[instrument_id] = stops_data + print(f"首次加载止盈止损信息: {instrument_id}") + return True + except Exception as e: + print(f"加载止盈止损信息失败: {e}") + + # 如果文件不存在,初始化空字典结构 + if instrument_id not in self.stop_order_dict: + self.stop_order_dict[instrument_id] = { + 'long': {'position': 0, 'entry_price': 0, 'stop_loss': 0, 'take_profit': 0, 'trailing_stop': 0}, + 'short': {'position': 0, 'entry_price': 0, 'stop_loss': 0, 'take_profit': 0, 'trailing_stop': 0} + } + print(f"初始化止盈止损结构: {instrument_id}") + + return False + + def check_stop_conditions(self, data): + """检查是否满足止盈止损条件""" + instrument_id = data['InstrumentID'].decode() + + # 如果该合约不在止盈止损字典中,直接返回 + if instrument_id not in self.stop_order_dict: + return + + current_bid = float(data['BidPrice1']) # 当前买价 + current_ask = float(data['AskPrice1']) # 当前卖价 + + stops = self.stop_order_dict[instrument_id] + + # 检查多头止盈止损 + if stops['long']['position'] > 0: + # 检查止损 + if stops['long']['stop_loss'] > 0 and current_bid <= stops['long']['stop_loss']: + print(f"触发多头止损: {instrument_id}, 价格: {current_bid}, 止损价: {stops['long']['stop_loss']}") + self.insert_order(data['ExchangeID'], data['InstrumentID'], current_bid-self.py, + stops['long']['position'], b'1', b'3') + # 清空多头持仓信息 + self.clear_position_info(instrument_id, 'long') + self.pos = 0 # 更新全局持仓状态 + + # 检查跟踪止损 - 新增的逻辑 + elif stops['long']['trailing_stop'] > 0 and current_bid < stops['long']['trailing_stop']: + print(f"触发多头跟踪止损: {instrument_id}, 价格: {current_bid}, 跟踪止损价: {stops['long']['trailing_stop']}") + self.insert_order(data['ExchangeID'], data['InstrumentID'], current_bid-self.py, + stops['long']['position'], b'1', b'3') + # 清空多头持仓信息 + self.clear_position_info(instrument_id, 'long') + self.pos = 0 # 更新全局持仓状态 + + # 检查止盈 + elif stops['long']['take_profit'] > 0 and current_bid >= stops['long']['take_profit']: + print(f"触发多头止盈: {instrument_id}, 价格: {current_bid}, 止盈价: {stops['long']['take_profit']}") + self.insert_order(data['ExchangeID'], data['InstrumentID'], current_bid-self.py, + stops['long']['position'], b'1', b'3') + # 清空多头持仓信息 + self.update_stop_order_dict(instrument_id, 'long', 0, 0, 0, 0) + self.pos = 0 # 更新全局持仓状态 + + # 更新跟踪止损价 - 只在价格上涨时更新 + elif stops['long']['trailing_stop'] > 0: + # 只有当前价格比之前设置的跟踪止损价高一定幅度时才更新 + new_trailing_stop = current_bid * (1 - self.trailing_stop_percent) + if new_trailing_stop > stops['long']['trailing_stop']: + self.update_stop_order_dict(instrument_id, 'long', None, None, None, None, new_trailing_stop) + print(f"更新多头跟踪止损: {instrument_id}, 新止损价: {new_trailing_stop}") + + # 检查空头止盈止损 + if stops['short']['position'] > 0: + # 检查止损 + if stops['short']['stop_loss'] > 0 and current_ask >= stops['short']['stop_loss']: + print(f"触发空头止损: {instrument_id}, 价格: {current_ask}, 止损价: {stops['short']['stop_loss']}") + self.insert_order(data['ExchangeID'], data['InstrumentID'], current_ask+self.py, + stops['short']['position'], b'0', b'3') + # 清空空头持仓信息 + self.update_stop_order_dict(instrument_id, 'short', 0, 0, 0, 0, 0) + self.pos = 0 # 更新全局持仓状态 + + # 检查跟踪止损 - 新增的逻辑 + elif stops['short']['trailing_stop'] > 0 and current_ask > stops['short']['trailing_stop']: + print(f"触发空头跟踪止损: {instrument_id}, 价格: {current_ask}, 跟踪止损价: {stops['short']['trailing_stop']}") + self.insert_order(data['ExchangeID'], data['InstrumentID'], current_ask+self.py, + stops['short']['position'], b'0', b'3') + # 清空空头持仓信息 + self.clear_position_info(instrument_id, 'short') + self.pos = 0 # 更新全局持仓状态 + + # 检查止盈 + elif stops['short']['take_profit'] > 0 and current_ask <= stops['short']['take_profit']: + print(f"触发空头止盈: {instrument_id}, 价格: {current_ask}, 止盈价: {stops['short']['take_profit']}") + self.insert_order(data['ExchangeID'], data['InstrumentID'], current_ask+self.py, + stops['short']['position'], b'0', b'3') + # 清空空头持仓信息 + self.update_stop_order_dict(instrument_id, 'short', 0, 0, 0, 0, 0) + self.pos = 0 # 更新全局持仓状态 + + # 更新跟踪止损价 - 只在价格下跌时更新 + elif stops['short']['trailing_stop'] > 0: + # 只有当前价格比之前设置的跟踪止损价低一定幅度时才更新 + new_trailing_stop = current_ask * (1 + self.trailing_stop_percent) + if new_trailing_stop < stops['short']['trailing_stop'] or stops['short']['trailing_stop'] == 0: + self.update_stop_order_dict(instrument_id, 'short', None, None, None, None, new_trailing_stop) + print(f"更新空头跟踪止损: {instrument_id}, 新止损价: {new_trailing_stop}") + + #保存数据 + + def clear_position_info(self, instrument_id, direction): + """ + 清空指定合约和方向的持仓信息 + + Args: + instrument_id: 合约ID + direction: 方向 'long' 或 'short' 或 'all' + """ + # 确保合约ID在字典中存在 + if instrument_id not in self.stop_order_dict: + return + + if direction == 'long' or direction == 'all': + # 清空多头持仓信息 + self.stop_order_dict[instrument_id]['long'] = { + 'position': 0, + 'entry_price': 0, + 'stop_loss': 0, + 'take_profit': 0, + 'trailing_stop': 0 + } + # 兼容旧代码 + if direction == 'long': + self.long_trailing_stop_price = 0 + self.sl_long_price = 0 + + if direction == 'short' or direction == 'all': + # 清空空头持仓信息 + self.stop_order_dict[instrument_id]['short'] = { + 'position': 0, + 'entry_price': 0, + 'stop_loss': 0, + 'take_profit': 0, + 'trailing_stop': 0 + } + # 兼容旧代码 + if direction == 'short': + self.short_trailing_stop_price = 0 + self.sl_shor_price = 0 + + # 同步全局持仓状态 + if direction == 'all': + self.pos = 0 + self.long_trailing_stop_price = 0 + self.short_trailing_stop_price = 0 + self.sl_long_price = 0 + self.sl_shor_price = 0 + + # 保存到文件 + self.save_stop_orders_to_file(instrument_id) + self.save_to_csv(instrument_id) + + print(f"已清空{instrument_id}的{direction}持仓信息") + +# 修改call_deepseek_model函数,移除JSON格式输出的要求,改为从普通文本响应中提取交易信号。 +def call_deepseek_model(data_df, trader_instance, max_retries=2): + """ + 调用deepseek-r1大模型分析订单流数据 + + Args: + data_df: 包含订单流数据的DataFrame + trader_instance: MyTrader实例,用于访问持仓信息 + max_retries: 最大重试次数 + + Returns: + dict: 包含交易信号的字典 + """ + # 直接从环境变量获取API密钥 + api_key = os.environ.get("OPENAI_API_KEY") or GLOBAL_LLM_CONFIG.get('api_key') + base_url = GLOBAL_LLM_CONFIG.get('base_url', "https://api.deepseek.com") + model_name = GLOBAL_LLM_CONFIG.get('model_name', "deepseek-reasoner") + + # 检查API密钥是否为空 + if not api_key: + print("错误: API密钥未设置,请在main函数中配置GLOBAL_LLM_CONFIG['api_key']") + return {"action": "不操作", "reason": "API密钥未设置", "confidence": 0, "stop_loss": 0, "take_profit": 0} + + # 将DataFrame转换为可读性好的文本,传递trader_instance + data_text = trader_instance.format_data_for_llm(data_df) + + # 构建提示词 + prompt = f""" + 作为期货交易员,基于以下市场数据做出交易决策: + + {data_text} + + 请重点考虑以下关键因素: + 1. 均线形态(5、10、20均线)的排列状态及价格位置 + 2. 价格趋势、波动性与关键支撑阻力位 + 3. 日内超涨超跌状态,寻找高胜率反转交易机会 + 4. K线组合形态,尤其关注反转信号和动量变化 + 5. 订单流趋势变化与力度 + 6. 买卖力量对比和资金流向 + 7. 当前持仓状态与盈亏情况 + 8. 风险回报比与止损止盈设置合理性 + 9. 适合的交易时机与市场环境判断 + + 【风险控制原则】: + - 严格控制每笔交易亏损不超过本金的1% + - 止损位设置应紧凑,一般不超过开仓价的0.3%-0.8% + - 风险回报比至少为1:1.5,建议争取1:2或更高 + - 在不明确的市场环境下,以保护资金为第一要务 + + 请根据市场状态和持仓情况,给出明确的交易指令: + 1. 交易方向: 开多/开空/平多/平空/不操作 + 2. 执行理由: 详细说明交易逻辑,结合技术形态、价格位置、订单流特征和市场状态,包括对当前持仓的处理方案 + 3. 置信度: 1-10的数字,必须是整数 + 4. 止损价: 明确的止损价格(必须是数字),确保亏损控制在合理范围内,不能过大 + 5. 止盈价: 明确的止盈价格(必须是数字),应至少是止损距离的1.5倍 + 6. 跟踪止损百分比: 0.0001-0.001之间的数字,根据市场波动性调整 + + 请按以下格式返回交易决策,格式必须严格匹配: + action: 开多/开空/平多/平空/不操作 + reason: 交易理由 + confidence: 置信度(1-10) + stop_loss: 止损价 + take_profit: 止盈价 + trailing_percent: 跟踪止损百分比(0.0001-0.001) + """ + + system_prompt = {"role": "system", + "content": "你是一位经验丰富的期货交易员,拥有多年实盘交易经验,精通订单流分析和技术形态识别。你的交易风格注重实战执行,善于制定明确的入场出场策略和风险控制方案。特别擅长日内波段交易和抄底摸顶策略,能准确捕捉超涨超跌反转机会和均线形态变化带来的交易信号,并能迅速做出果断决策。你综合考虑市场情绪、技术指标与价格行为,在保护资金安全的前提下寻求最佳交易机会。根据当前市场状态和持仓情况,你能给出明确的交易执行方案、止损止盈设置以及仓位管理建议。请确保以指定的格式返回交易决策。"} + + # 添加重试机制 + retries = 0 + while retries <= max_retries: + try: + # 如果不是第一次尝试,输出重试信息 + if retries > 0: + print(f"正在进行第 {retries} 次重试...") + + # 调试信息 + print(f"使用API参数: base_url={base_url}, model={model_name}") + + # 添加明显的提示信息,表示正在调用大模型API + print("\n============================================") + print("【正在调用大模型API进行交易分析,请稍候...】") + print("============================================\n") + + # 记录开始时间 + api_start_time = time.time() + + # 使用OpenAI客户端格式调用API + client = OpenAI(api_key=api_key, base_url=base_url) + + response = client.chat.completions.create( + model=model_name, + messages=[ + system_prompt, + {"role": "user", "content": prompt} + ], + temperature=0.1, + # 移除JSON格式输出的要求 + max_tokens=8192, + timeout=60 # 将超时时间从30秒增加到60秒 + ) + + # 计算API调用耗时 + api_elapsed = time.time() - api_start_time + + # 提取模型输出的内容 + model_response = response.choices[0].message.content + print(f"模型响应耗时: {api_elapsed:.2f}秒") + print("模型响应前100字符: " + model_response[:100] + "...") + + # 添加明显的提示信息,表示API调用已完成 + print("\n============================================") + print("【大模型API调用完成】") + print("============================================\n") + + # 从文本中解析出交易信号 + try: + trading_signal = parse_trading_signal(model_response) + return trading_signal + except Exception as parse_err: + print(f"解析模型响应出错: {parse_err}") + # 尝试从自由文本中提取关键信息 + return extract_trading_signal_from_text(model_response) + + except Exception as e: + retries += 1 + if retries <= max_retries: + print(f"调用大模型API出错: {e}") + print(f"将在3秒后重试...") + time.sleep(3) # 等待3秒后重试 + else: + print(f"已达到最大重试次数 ({max_retries}),调用大模型API失败") + print(f"错误详情: {e}") + print("\n请检查以下几点:") + print("1. API密钥格式是否正确,应以'sk-'开头") + print("2. 确认已安装最新版本的openai库: pip install --upgrade openai") + print("3. 确认您的API密钥对应的模型是否为deepseek-reasoner") + # 返回默认的不操作信号 + return {"action": "不操作", "reason": f"API调用失败: {str(e)[:100]}", "confidence": 0, "stop_loss": 0, "take_profit": 0} + + # 如果所有重试都失败了,返回默认值 + return {"action": "不操作", "reason": "API调用重试耗尽", "confidence": 0, "stop_loss": 0, "take_profit": 0} + +def parse_trading_signal(text): + """ + 从文本格式的模型响应中解析出交易信号 + + Args: + text: 模型响应文本 + + Returns: + dict: 包含交易信号的字典 + """ + lines = text.strip().split('\n') + trading_signal = {} + + for line in lines: + if ':' in line: + key, value = line.split(':', 1) + key = key.strip().lower() + value = value.strip() + + if key == 'action': + trading_signal['action'] = value + elif key == 'reason': + trading_signal['reason'] = value + elif key == 'confidence': + try: + trading_signal['confidence'] = int(value) + except ValueError: + # 尝试从文本中提取数字 + import re + match = re.search(r'\d+', value) + if match: + trading_signal['confidence'] = int(match.group()) + else: + trading_signal['confidence'] = 0 + elif key == 'stop_loss': + try: + trading_signal['stop_loss'] = float(value) + except ValueError: + # 尝试从文本中提取数字 + import re + match = re.search(r'\d+(\.\d+)?', value) + if match: + trading_signal['stop_loss'] = float(match.group()) + else: + trading_signal['stop_loss'] = 0 + elif key == 'take_profit': + try: + trading_signal['take_profit'] = float(value) + except ValueError: + # 尝试从文本中提取数字 + import re + match = re.search(r'\d+(\.\d+)?', value) + if match: + trading_signal['take_profit'] = float(match.group()) + else: + trading_signal['take_profit'] = 0 + elif key == 'trailing_percent' or key == 'trailing_stop_percent': + try: + value_float = float(value) + # 确保值在合理范围内 + if 0.0005 <= value_float <= 0.015: + trading_signal['trailing_percent'] = value_float + else: + # 如果值不在预期范围内,尝试判断是否使用了百分比格式 + if value_float >= 0.05 and value_float <= 1.5: + # 可能是百分比格式,转换为小数 + trading_signal['trailing_percent'] = value_float / 100 + else: + # 设置为默认值 + trading_signal['trailing_percent'] = 0.005 + except ValueError: + # 尝试从文本中提取数字 + import re + match = re.search(r'\d+(\.\d+)?', value) + if match: + try: + trailing_value = float(match.group()) + if trailing_value >= 0.5 and trailing_value <= 10: + trading_signal['trailing_percent'] = trailing_value / 100 + else: + trading_signal['trailing_percent'] = trailing_value + except: + trading_signal['trailing_percent'] = 0.02 + else: + trading_signal['trailing_percent'] = 0.02 + + # 检查是否有缺失的字段,如果有,设置默认值 + if 'action' not in trading_signal: + trading_signal['action'] = '不操作' + if 'reason' not in trading_signal: + trading_signal['reason'] = '未提供理由' + if 'confidence' not in trading_signal: + trading_signal['confidence'] = 0 + if 'stop_loss' not in trading_signal: + trading_signal['stop_loss'] = 0 + if 'take_profit' not in trading_signal: + trading_signal['take_profit'] = 0 + if 'trailing_percent' not in trading_signal: + trading_signal['trailing_percent'] = 0.005 # 修改默认值 + + return trading_signal + +def extract_trading_signal_from_text(text): + """ + 从自由格式文本中尝试提取交易信号 + + Args: + text: 模型响应文本 + + Returns: + dict: 包含交易信号的字典 + """ + # 默认交易信号 + trading_signal = { + "action": "不操作", + "reason": "无法解析模型响应", + "confidence": 0, + "stop_loss": 0, + "take_profit": 0, + "trailing_percent": 0.005 # 更新默认的跟踪止损百分比 + } + + # 尝试判断交易方向 + text_lower = text.lower() + if "开多" in text_lower: + trading_signal["action"] = "开多" + elif "开空" in text_lower: + trading_signal["action"] = "开空" + elif "平多" in text_lower: + trading_signal["action"] = "平多" + elif "平空" in text_lower: + trading_signal["action"] = "平空" + elif "不操作" in text_lower or "观望" in text_lower: + trading_signal["action"] = "不操作" + + # 尝试从文本中提取置信度 + import re + confidence_matches = re.findall(r'置信度[::]\s*(\d+)', text_lower) + if confidence_matches: + try: + trading_signal["confidence"] = int(confidence_matches[0]) + except ValueError: + pass + + # 尝试提取止损价 + stop_loss_matches = re.findall(r'止损价[::]\s*(\d+(\.\d+)?)', text_lower) + if stop_loss_matches: + try: + trading_signal["stop_loss"] = float(stop_loss_matches[0][0]) + except ValueError: + pass + + # 尝试提取止盈价 + take_profit_matches = re.findall(r'止盈价[::]\s*(\d+(\.\d+)?)', text_lower) + if take_profit_matches: + try: + trading_signal["take_profit"] = float(take_profit_matches[0][0]) + except ValueError: + pass + + # 尝试提取跟踪止损百分比 + trailing_matches = re.findall(r'跟踪止损百分比[::]\s*(\d+(\.\d+)?)', text_lower) + if not trailing_matches: + trailing_matches = re.findall(r'跟踪百分比[::]\s*(\d+(\.\d+)?)', text_lower) + + if trailing_matches: + try: + trailing_value = float(trailing_matches[0][0]) + # 判断是否为百分比格式 + if trailing_value >= 0.5 and trailing_value <= 10: + trading_signal["trailing_percent"] = trailing_value / 100 + else: + trading_signal["trailing_percent"] = trailing_value + except ValueError: + pass + + # 提取理由 + reason_matches = re.findall(r'理由[::]\s*(.*?)(?=\n|$)', text_lower) + if reason_matches: + trading_signal["reason"] = reason_matches[0] + + return trading_signal + +# 修改run_trader函数,不再传递llm_config参数 +def run_trader(broker_id, td_server, investor_id, password, app_id, auth_code, md_queue=None, page_dir='', private_resume_type=2, public_resume_type=2, load_history=False, history_rows=1000,trader_rows=10): + my_trader = MyTrader( + broker_id, + td_server, + investor_id, + password, + app_id, + auth_code, + md_queue, + page_dir, + private_resume_type, + public_resume_type + ) + + # 设置历史数据加载参数 + my_trader.load_history = load_history + my_trader.history_rows = history_rows + my_trader.trader_rows = trader_rows + my_trader.Join() + +# 修改主函数中的配置和调用方式 +if __name__ == '__main__': + + #公众号:松鼠Quant + #主页:www.quant789.com + #本策略仅作学习交流使用,实盘交易盈亏投资者个人负责!!! + #版权归松鼠Quant所有,禁止转发、转卖源码违者必究。 + + #注意:运行前请先安装好algoplus, + # pip install AlgoPlus + #http://www.algo.plus/ctp/python/0103001.html + + + # 配置大模型参数 - 直接通过环境变量设置 + import os + # 设置您的实际API密钥 + api_key = "" # 请确保使用有效的密钥 + os.environ["OPENAI_API_KEY"] = api_key + + # 同时设置到全局变量中 + GLOBAL_LLM_CONFIG['api_key'] = api_key + GLOBAL_LLM_CONFIG['base_url'] = "https://api.deepseek.com" + GLOBAL_LLM_CONFIG['model_name'] = "deepseek-reasoner" + # 历史数据加载配置 + LOAD_HISTORY = False # 是否加载历史数据 + HISTORY_ROWS = 30 # 加载历史文件中数据量 + TRADER_ROWS = 10 # 当tader_df里的数据大于10行时开始计算指标及触发AI模型 + # 设置K线时间粒度 + BAR_RESAMPLE_RULE = '1T' # 1分钟K线,可以修改为'5T'(5分钟),'15T'(15分钟)等,也可用'5S'(5秒),'30S'(30秒)或'1H'(1小时),'2H'(2小时),'4H'(4小时),'1D'(1天) + + # 测试API连接 + print(f"测试API连接,使用密钥: {api_key[:5]}...{api_key[-5:]}") + try: + client = OpenAI(api_key=api_key, base_url="https://api.deepseek.com") + response = client.chat.completions.create( + model="deepseek-reasoner", + messages=[ + {"role": "system", "content": "你是一个助手"}, + {"role": "user", "content": "测试"} + ], + stream=True, # 新增此行 + max_tokens=10 + ) + print("API连接测试成功!") + except Exception as e: + print(f"API连接测试失败: {e}") + import traceback + traceback.print_exc() + + #用simnow模拟,不要忘记屏蔽下方实盘的future_account字典 + future_account = get_simulate_account( + investor_id='', # simnow账户,注意是登录账户的ID,SIMNOW个人首页查看 + password='', # simnow密码 + server_name='电信1', # 电信1、电信2、移动、TEST、N视界 + subscribe_list=[b'au2506'], # 合约列表 + ) + + # #实盘用这个,不要忘记屏蔽上方simnow的future_account字典 + # future_account = FutureAccount( + # broker_id='', # 期货公司BrokerID + # server_dict={'TDServer': "ip:port", 'MDServer': 'ip:port'}, # TDServer为交易服务器,MDServer为行情服务器。服务器地址格式为"ip:port。" + # reserve_server_dict={}, # 备用服务器地址 + # investor_id='', # 账户 + # password='', # 密码 + # app_id='simnow_client_test', # 认证使用AppID + # auth_code='0000000000000000', # 认证使用授权码 + # subscribe_list=[b'rb2405'], # 订阅合约列表 + # md_flow_path='./log', # MdApi流文件存储地址,默认MD_LOCATION + # td_flow_path='./log', # TraderApi流文件存储地址,默认TD_LOCATION + # ) + + print('开始',len(future_account.subscribe_list)) + # 共享队列 + share_queue = Queue(maxsize=200) + + # 行情进程 + md_process = Process(target=run_tick_engine, args=(future_account, [share_queue])) + + # 交易进程 - 增加历史数据加载参数 + trader_process = Process(target=run_trader, args=( + future_account.broker_id, + future_account.server_dict['TDServer'], + future_account.investor_id, + future_account.password, + future_account.app_id, + future_account.auth_code, + share_queue, # 队列 + future_account.td_flow_path, + 2, # private_resume_type + 2, # public_resume_type + LOAD_HISTORY, # 传递历史数据加载参数 + HISTORY_ROWS, # 传递历史数据行数参数 + TRADER_ROWS, # 传递最低计算阈值 + )) + + md_process.start() + trader_process.start() + + md_process.join() + trader_process.join() + + \ No newline at end of file diff --git a/1.交易策略/999.其他策略/4.松鼠SF20_基于LLM的订单流日内交易策略/使用文档/3.28版本/这里填写好就可以跑了.png b/1.交易策略/999.其他策略/4.松鼠SF20_基于LLM的订单流日内交易策略/使用文档/3.28版本/这里填写好就可以跑了.png new file mode 100644 index 0000000..96ad4e6 Binary files /dev/null and b/1.交易策略/999.其他策略/4.松鼠SF20_基于LLM的订单流日内交易策略/使用文档/3.28版本/这里填写好就可以跑了.png differ diff --git a/1.交易策略/999.其他策略/4.松鼠SF20_基于LLM的订单流日内交易策略/使用文档/3.31版本/专享策略20_o3mini.py b/1.交易策略/999.其他策略/4.松鼠SF20_基于LLM的订单流日内交易策略/使用文档/3.31版本/专享策略20_o3mini.py new file mode 100644 index 0000000..733d501 --- /dev/null +++ b/1.交易策略/999.其他策略/4.松鼠SF20_基于LLM的订单流日内交易策略/使用文档/3.31版本/专享策略20_o3mini.py @@ -0,0 +1,2377 @@ +''' +#公众号:松鼠Quant +#主页:www.quant789.com +#本策略仅作学习交流使用,实盘交易盈亏投资者个人负责!!! +#版权归松鼠Quant所有,禁止转发、转卖源码违者必究。 + +该代码的主要目的是处理Tick数据并生成交易信号。代码中定义了一个tickcome函数,它接收到Tick数据后会进行一系列的处理,包括构建Tick字典、更新上一个Tick的成交量、保存Tick数据、生成K线数据等。其中涉及到的一些函数有: + +on_tick(tick): 处理单个Tick数据,根据Tick数据生成K线数据。 +tickdata(df, symbol): 处理Tick数据,生成K线数据。 +orderflow_df_new(df_tick, df_min, symbol): 处理Tick和K线数据,生成订单流数据。 +GetOrderFlow_dj(kData): 计算订单流的信号指标。 +除此之外,代码中还定义了一个MyTrader类,继承自TraderApiBase,用于实现交易相关的功能。 +#公众号:松鼠Quant +#主页:www.quant789.com +#本策略仅作学习交流使用,实盘交易盈亏投资者个人负责!!! +#版权归松鼠Quant所有,禁止转发、转卖源码违者必究。 +''' +from multiprocessing import Process, Queue +from AlgoPlus.CTP.MdApi import run_tick_engine +from AlgoPlus.CTP.FutureAccount import get_simulate_account +from AlgoPlus.CTP.FutureAccount import FutureAccount +from AlgoPlus.CTP.TraderApiBase import TraderApiBase +from AlgoPlus.ta.time_bar import tick_to_bar +import pandas as pd +from datetime import datetime +from datetime import time as s_time +import operator +import time +import numpy as np +import os +import re +import json +import requests # 添加requests库用于API调用 +from openai import OpenAI # 导入OpenAI客户端 +import threading +from queue import Queue as ThreadQueue +import warnings +warnings.filterwarnings("ignore", category=FutureWarning) +import copy +import math +import re # 新增 +import logging # 新增 +from logging.handlers import RotatingFileHandler # 新增 + +# 在文件顶部定义全局变量 +tickdatadict = {} # 存储Tick数据的字典 +quotedict = {} # 存储行情数据的字典 +ofdatadict = {} # 存储K线数据的字典 +trader_df = pd.DataFrame({}) # 存储交易数据的DataFrame对象 +previous_volume = {} # 上一个Tick的成交量 +tsymbollist={} +# 全局LLM配置变量 +GLOBAL_LLM_CONFIG = {} # 全局大模型配置参数 +# 全局交易信号队列,用于存储AI模型生成的交易信号 +AI_SIGNAL_QUEUE = ThreadQueue() +# 标记是否有AI线程正在运行 +AI_THREAD_RUNNING = False +# 不再需要单独的K线时间粒度全局变量,它已经被整合到GLOBAL_LLM_CONFIG中 + +# 设置日志系统 +def setup_logging(log_folder='logs'): + # 确保日志文件夹存在 + if not os.path.exists(log_folder): + os.makedirs(log_folder) + + # 创建日志格式 + formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s') + + # 设置AI分析日志 + ai_logger = logging.getLogger('ai_analysis') + ai_logger.setLevel(logging.INFO) + + # 设置带有文件循环的文件处理器 + ai_file_handler = RotatingFileHandler( + os.path.join(log_folder, 'ai_analysis.log'), + maxBytes=10*1024*1024, # 10MB + backupCount=5 + ) + ai_file_handler.setFormatter(formatter) + ai_logger.addHandler(ai_file_handler) + + # 设置交易信号日志 + signal_logger = logging.getLogger('trading_signals') + signal_logger.setLevel(logging.INFO) + + signal_file_handler = RotatingFileHandler( + os.path.join(log_folder, 'trading_signals.log'), + maxBytes=10*1024*1024, # 10MB + backupCount=5 + ) + signal_file_handler.setFormatter(formatter) + signal_logger.addHandler(signal_file_handler) + + # 设置止损止盈日志 + stoploss_logger = logging.getLogger('stoploss') + stoploss_logger.setLevel(logging.INFO) + + stoploss_file_handler = RotatingFileHandler( + os.path.join(log_folder, 'stoploss.log'), + maxBytes=10*1024*1024, # 10MB + backupCount=5 + ) + stoploss_file_handler.setFormatter(formatter) + stoploss_logger.addHandler(stoploss_file_handler) + + # 返回三个日志记录器 + return ai_logger, signal_logger, stoploss_logger + +# 全局日志记录器 +AI_LOGGER, SIGNAL_LOGGER, STOPLOSS_LOGGER = setup_logging() + +def tickcome(md_queue): + global previous_volume + + data=md_queue + instrument_id = data['InstrumentID'].decode() # 品种代码 + ActionDay = data['ActionDay'].decode() # 交易日日期 + update_time = data['UpdateTime'].decode() # 更新时间 + #zzg_quant + update_millisec = str(data['UpdateMillisec']) # 更新毫秒数 + created_at = ActionDay[:4] + '-' + ActionDay[4:6] + '-' + ActionDay[6:] + ' ' + update_time + '.' + update_millisec #创建时间 + # 构建tick字典 + tick = { + 'symbol': instrument_id, # 品种代码和交易所ID + 'created_at':datetime.strptime(created_at, "%Y-%m-%d %H:%M:%S.%f"), + #'created_at': created_at, # 创建时间 + 'price': float(data['LastPrice']), # 最新价 + 'last_volume': int(data['Volume']) - previous_volume.get(instrument_id, 0) if previous_volume.get(instrument_id, 0) != 0 else 0, # 瞬时成交量 + 'bid_p': float(data['BidPrice1']), # 买价 + 'bid_v': int(data['BidVolume1']), # 买量 + 'ask_p': float(data['AskPrice1']), # 卖价 + 'ask_v': int(data['AskVolume1']), # 卖量 + 'UpperLimitPrice': float(data['UpperLimitPrice']), # 涨停价 + 'LowerLimitPrice': float(data['LowerLimitPrice']), # 跌停价 + 'TradingDay': data['TradingDay'].decode(), # 交易日日期 + 'cum_volume': int(data['Volume']), # 最新总成交量 + 'cum_amount': float(data['Turnover']), # 最新总成交额 + 'cum_position': int(data['OpenInterest']), # 合约持仓量 + } + # 更新上一个Tick的成交量 + previous_volume[instrument_id] = int(data['Volume']) + if tick['last_volume']>0: + #print(tick['created_at'],'vol:',tick['last_volume']) + # 处理Tick数据 + on_tick(tick) + + +def can_time(hour, minute): + hour = str(hour) + minute = str(minute) + if len(minute) == 1: + minute = "0" + minute + return int(hour + minute) + +def on_tick(tick): + + tm=can_time(tick['created_at'].hour,tick['created_at'].minute) + #print(tick['symbol']) + #print(1) + #if tm>1500 and tm<2100 : + # return + if tick['last_volume']==0: + return + quotes = tick + timetick=str(tick['created_at']).replace('+08:00', '') + tsymbol=tick['symbol'] + if tsymbol not in tsymbollist.keys(): + # 获取tick的买卖价和买卖量 + #zzg_quant + tsymbollist[tsymbol]=tick + bid_p=quotes['bid_p'] + ask_p=quotes['ask_p'] + bid_v=quotes['bid_v'] + ask_v=quotes['ask_v'] + else: + # 获取上一个tick的买卖价和买卖量 + rquotes =tsymbollist[tsymbol] + bid_p=rquotes['bid_p'] + ask_p=rquotes['ask_p'] + bid_v=rquotes['bid_v'] + ask_v=rquotes['ask_v'] + tsymbollist[tsymbol]=tick + tick_dt=pd.DataFrame({'datetime':timetick,'symbol':tick['symbol'],'mainsym':tick['symbol'].rstrip('0123456789').upper(),'lastprice':tick['price'], + 'vol':tick['last_volume'], + 'bid_p':bid_p,'ask_p':ask_p,'bid_v':bid_v,'ask_v':ask_v},index=[0]) + sym = tick_dt['symbol'][0] + #print(tick_dt) + + # 直接调用tickdata,不传递resample_rule参数,让其自行从全局配置获取 + tickdata(tick_dt, sym) + +#公众号:松鼠Quant +#主页:www.quant789.com +#本策略仅作学习交流使用,实盘交易盈亏投资者个人负责!!! +#版权归松鼠Quant所有,禁止转发、转卖源码违者必究。 + +def data_of(df): + global trader_df + # 将df数据合并到trader_df中 + trader_df = pd.concat([trader_df, df], ignore_index=True) + #print('trader_df: ', len(trader_df)) + #print(trader_df) + +def process(bidDict, askDict, symbol): + try: + # 尝试从quotedict中获取对应品种的报价数据 + dic = quotedict[symbol] + bidDictResult = dic['bidDictResult'] + askDictResult = dic['askDictResult'] + except: + # 如果获取失败,则初始化bidDictResult和askDictResult为空字典 + bidDictResult, askDictResult = {}, {} + + # 将所有买盘字典和卖盘字典的key合并,并按升序排序 + sList = sorted(set(list(bidDict.keys()) + list(askDict.keys()))) + + # 遍历所有的key,将相同key的值进行累加 + for s in sList: + if s in bidDict: + if s in bidDictResult: + bidDictResult[s] = int(bidDict[s]) + bidDictResult[s] + else: + bidDictResult[s] = int(bidDict[s]) + if s not in askDictResult: + askDictResult[s] = 0 + else: + if s in askDictResult: + askDictResult[s] = int(askDict[s]) + askDictResult[s] + else: + askDictResult[s] = int(askDict[s]) + if s not in bidDictResult: + bidDictResult[s] = 0 + + # 构建包含bidDictResult和askDictResult的字典,并存入quotedict中 + df = {'bidDictResult': bidDictResult, 'askDictResult': askDictResult} + quotedict[symbol] = df + + return bidDictResult, askDictResult +#公众号:松鼠Quant +#主页:www.quant789.com +#本策略仅作学习交流使用,实盘交易盈亏投资者个人负责!!! +#版权归松鼠Quant所有,禁止转发、转卖源码违者必究。 + + +def tickdata(df, symbol): + tickdata =pd.DataFrame({'datetime':df['datetime'],'symbol':df['symbol'],'lastprice':df['lastprice'], + 'volume':df['vol'],'bid_p':df['bid_p'],'bid_v':df['bid_v'],'ask_p':df['ask_p'],'ask_v':df['ask_v']}) + try: + if symbol in tickdatadict.keys(): + rdf=tickdatadict[symbol] + rdftm=pd.to_datetime(rdf['bartime'][0]).strftime('%Y-%m-%d %H:%M:%S') + now=str(tickdata['datetime'][0]) + if now>rdftm: + try: + oo=ofdatadict[symbol] + data_of(oo) + #print('oo',oo) + if symbol in quotedict.keys(): + quotedict.pop(symbol) + if symbol in tickdatadict.keys(): + tickdatadict.pop(symbol) + if symbol in ofdatadict.keys(): + ofdatadict.pop(symbol) + except IOError as e: + print('rdftm捕获到异常',e) + tickdata['bartime'] = pd.to_datetime(tickdata['datetime']) + tickdata['open'] = tickdata['lastprice'] + tickdata['high'] = tickdata['lastprice'] + tickdata['low'] = tickdata['lastprice'] + tickdata['close'] = tickdata['lastprice'] + tickdata['starttime'] = tickdata['datetime'] + else: + tickdata['bartime'] = rdf['bartime'] + tickdata['open'] = rdf['open'] + tickdata['high'] = max(tickdata['lastprice'].values,rdf['high'].values) + tickdata['low'] = min(tickdata['lastprice'].values,rdf['low'].values) + tickdata['close'] = tickdata['lastprice'] + tickdata['volume']=df['vol']+rdf['volume'].values + tickdata['starttime'] = rdf['starttime'] + else : + print('新bar的第一个tick进入') + tickdata['bartime'] = pd.to_datetime(tickdata['datetime']) + tickdata['open'] = tickdata['lastprice'] + tickdata['high'] = tickdata['lastprice'] + tickdata['low'] = tickdata['lastprice'] + tickdata['close'] = tickdata['lastprice'] + tickdata['starttime'] = tickdata['datetime'] + except IOError as e: + print('捕获到异常',e) + + + tickdata['bartime'] = pd.to_datetime(tickdata['bartime']) + # 直接从全局配置获取resample_rule + resample_rule = GLOBAL_LLM_CONFIG.get('bar_resample_rule') + + # 使用resample_rule生成K线 + bardata = tickdata.resample(on = 'bartime', rule = resample_rule, label = 'right', closed = 'right').agg({'starttime':'first','symbol':'last','open':'first','high':'max','low':'min','close':'last','volume':'sum'}).reset_index(drop = False) + bardata =bardata.dropna().reset_index(drop = True) + bardata['bartime'] = pd.to_datetime(bardata['bartime'][0]).strftime('%Y-%m-%d %H:%M:%S') + tickdatadict[symbol]=bardata + tickdata['volume']=df['vol'].values + #print(bardata['symbol'].values,bardata['bartime'].values) + orderflow_df_new(tickdata,bardata,symbol) + # time.sleep(0.5) + +#公众号:松鼠Quant +#主页:www.quant789.com +#本策略仅作学习交流使用,实盘交易盈亏投资者个人负责!!! +#版权归松鼠Quant所有,禁止转发、转卖源码违者必究。 + +def orderflow_df_new(df_tick,df_min,symbol): + startArray = pd.to_datetime(df_min['starttime']).values + voluememin= df_min['volume'].values + highs=df_min['high'].values + lows=df_min['low'].values + opens=df_min['open'].values + closes=df_min['close'].values + #endArray = pd.to_datetime(df_min['bartime']).values + endArray = df_min['bartime'].values + #print(endArray) + deltaArray = np.zeros((len(endArray),)) + tTickArray = pd.to_datetime(df_tick['datetime']).values + bp1TickArray = df_tick['bid_p'].values + ap1TickArray = df_tick['ask_p'].values + lastTickArray = df_tick['lastprice'].values + volumeTickArray = df_tick['volume'].values + symbolarray = df_tick['symbol'].values + indexFinal = 0 + for index,tEnd in enumerate(endArray): + dt=endArray[index] + start = startArray[index] + bidDict = {} + askDict = {} + bar_vol=voluememin[index] + bar_close=closes[index] + bar_open=opens[index] + bar_low=lows[index] + bar_high=highs[index] + bar_symbol=symbolarray[index] + # for indexTick in range(indexFinal,len(df_tick)): + # if tTickArray[indexTick] >= tEnd: + # break + # elif (tTickArray[indexTick] >= start) & (tTickArray[indexTick] < tEnd): + Bp = round(bp1TickArray[0],4) + Ap = round(ap1TickArray[0],4) + LastPrice = round(lastTickArray[0],4) + Volume = volumeTickArray[0] + if LastPrice >= Ap: + if str(LastPrice) in askDict.keys(): + askDict[str(LastPrice)] += Volume + else: + askDict[str(LastPrice)] = Volume + if LastPrice <= Bp: + if str(LastPrice) in bidDict.keys(): + bidDict[str(LastPrice)] += Volume + else: + bidDict[str(LastPrice)] = Volume + # indexFinal = indexTick + bidDictResult,askDictResult = process(bidDict,askDict,symbol) + bidDictResult=dict(sorted(bidDictResult.items(),key=operator.itemgetter(0))) + askDictResult=dict(sorted(askDictResult.items(),key=operator.itemgetter(0))) + prinslist=list(bidDictResult.keys()) + asklist=list(askDictResult.values()) + bidlist=list(bidDictResult.values()) + delta=(sum(askDictResult.values()) - sum(bidDictResult.values())) + #print(prinslist,asklist,bidlist) + #print(len(prinslist),len(bidDictResult),len(askDictResult)) + df=pd.DataFrame({'price':pd.Series([prinslist]),'Ask':pd.Series([asklist]),'Bid':pd.Series([bidlist])}) + #df=pd.DataFrame({'price':pd.Series(bidDictResult.keys()),'Ask':pd.Series(askDictResult.values()),'Bid':pd.Series(bidDictResult.values())}) + df['symbol']=bar_symbol + df['datetime']=dt + df['delta']=str(delta) + df['close']=bar_close + df['open']=bar_open + df['high']=bar_high + df['low']=bar_low + df['volume']=bar_vol + #df['ticktime']=tTickArray[0] + df['dj'] = GetOrderFlow_dj(df) + ofdatadict[symbol]=df + +#公众号:松鼠Quant +#主页:www.quant789.com +#本策略仅作学习交流使用,实盘交易盈亏投资者个人负责!!! +#版权归松鼠Quant所有,禁止转发、转卖源码违者必究。 + +def GetOrderFlow_dj(kData): + Config = { + 'Value1': 3, + 'Value2': 3, + 'Value3': 3, + 'Value4': True, + } + aryData = kData + djcout = 0 + + # 遍历kData中的每一行,计算djcout指标 + for index, row in aryData.iterrows(): + kItem = aryData.iloc[index] + high = kItem['high'] + low = kItem['low'] + close = kItem['close'] + open = kItem['open'] + dtime = kItem['datetime'] + price_s = kItem['price'] + Ask_s = kItem['Ask'] + Bid_s = kItem['Bid'] + delta = kItem['delta'] + + price_s = price_s + Ask_s = Ask_s + Bid_s = Bid_s + + gj = 0 + xq = 0 + gxx = 0 + xxx = 0 + + # 遍历price_s中的每一个元素,计算相关指标 + for i in np.arange(0, len(price_s), 1): + duiji = { + 'price': 0, + 'time': 0, + 'longshort': 0, + } + + if i == 0: + delta = delta + + order= { + "Price":price_s[i], + "Bid":{ "Value":Bid_s[i]}, + "Ask":{ "Value":Ask_s[i]} + } + #空头堆积 + if i >= 0 and i < len(price_s) - 1: + if (order["Bid"]["Value"] > Ask_s[i + 1] * int(Config['Value1'])): + gxx += 1 + gj += 1 + if gj >= int(Config['Value2']) and Config['Value4'] == True: + duiji['price'] = price_s[i] + duiji['time'] = dtime + duiji['longshort'] = -1 + if float(duiji['price']) > 0: + djcout += -1 + else: + gj = 0 + #多头堆积 + if i >= 1 and i <= len(price_s) - 1: + if (order["Ask"]["Value"] > Bid_s[i - 1] * int(Config['Value1'])): + xq += 1 + xxx += 1 + if xq >= int(Config['Value2']) and Config['Value4'] == True: + duiji['price'] = price_s[i] + duiji['time'] = dtime + duiji['longshort'] = 1 + if float(duiji['price']) > 0: + djcout += 1 + else: + xq = 0 + + # 返回计算得到的djcout值 + return djcout + +#交易程序--------------------------------------------------------------------------------------------------------------------------------------------------------------------- + +class MyTrader(TraderApiBase): + def __init__(self, broker_id, td_server, investor_id, password, app_id, auth_code, md_queue=None, page_dir='', private_resume_type=2, public_resume_type=2): + # Cython类不使用super().__init__()方式调用父类初始化方法 + # TraderApiBase.__init__会由Cython自动处理 + + self.py=30 #设置委托价格的偏移,更加容易促成成交。仅螺纹,其他品种根据最小点波动,自己设置 + self.cont_df=0 + self.trailing_stop_percent = 0.005 #跟踪出场参数,从0.02减小到0.005 + self.fixed_stop_loss_percent = 0.01 #固定出场参数 + self.dj_X=1 #开仓的堆积参数 + + self.pos=0 + self.Lots=1 #下单手数 + self.short_trailing_stop_price = 0 + self.long_trailing_stop_price = 0 + self.sl_long_price=0 + self.sl_shor_price=0 + self.out_long=0 + self.out_short=0 + self.clearing_executed=False + self.day_closed = False # 添加日内平仓标志 + self.kgdata = True #历史数据加载一次 + self.holddata=True #持仓数据加载一次 + self.use_ai_model = True # 是否使用AI模型来分析 + + # 新增止盈止损字典,按合约ID索引 + self.stop_order_dict = {} + + # 新增历史数据加载相关参数 + self.load_history = False # 是否加载历史数据 + self.history_rows = 30 # 默认加载30行历史数据 + self.trader_rows = 10 # 当tader_df里的数据大于10行时开始计算指标及触发AI模型 + + def load_history_data(self, instrument_id): + """ + 加载历史数据 + + Args: + instrument_id: 合约ID + """ + if not self.load_history: + return + + try: + # 不再只提取英文字母,使用完整的合约代码 + symbol = str(instrument_id) + json_file_path = f"traderdata/{symbol}_ofdata.json" + + # 检查traderdata目录是否存在 + if not os.path.exists("traderdata"): + print(f"traderdata目录不存在,创建目录") + os.makedirs("traderdata") + + if os.path.exists(json_file_path): + try: + # 读取JSON文件,使用lines=True确保正确读取每行JSON + df = pd.read_json(json_file_path, lines=True) + + if len(df) == 0: + print(f"历史数据文件为空: {json_file_path}") + print("将使用实时数据开始交易") + return False + + # 如果数据行数超过设定的历史行数,只取最后N行 + if len(df) > self.history_rows: + df = df.tail(self.history_rows) + print(f"历史数据超过设定行数,仅加载最后{self.history_rows}行") + + # 更新全局trader_df + global trader_df + trader_df = df + + print(f"\n===== 历史数据加载成功 =====") + print(f"合约: {instrument_id}") + print(f"数据行数: {len(df)}行") + print(f"数据时间范围: {df['datetime'].iloc[0]} 到 {df['datetime'].iloc[-1]}") + print(f"最新价格: {df['close'].iloc[-1]}") + print(f"最新成交量: {df['volume'].iloc[-1]}") + print("===========================\n") + + # 更新cont_df + self.cont_df = len(df) + + # 计算日均线 + if len(df) > 0: + df['dayma'] = df['close'].mean() + + # 计算累积的delta值 + df['delta'] = df['delta'].astype(float) + df['delta累计'] = df['delta'].cumsum() + + return True + except Exception as e: + print(f"\n===== 历史数据加载错误 =====") + print(f"合约: {instrument_id}") + print(f"读取JSON错误: {e}") + print("将使用实时数据开始交易") + print("===========================\n") + return False + else: + print(f"\n===== 历史数据加载提示 =====") + print(f"合约: {instrument_id}") + print(f"未找到历史数据文件: {json_file_path}") + print("将使用实时数据开始交易") + print("===========================\n") + return False + + except Exception as e: + print(f"\n===== 历史数据加载错误 =====") + print(f"合约: {instrument_id}") + print(f"错误信息: {e}") + print("将使用实时数据开始交易") + print("===========================\n") + return False + + #读取保存的数据 + def read_to_csv(self,symbol): + # 文件夹路径和文件路径 + # 使用完整的合约代码 + symbol = str(symbol) + folder_path = "traderdata" + file_path = os.path.join(folder_path, f"{symbol}traderdata.csv") + # 如果文件夹不存在则创建 + if not os.path.exists(folder_path): + os.makedirs(folder_path) + + # 读取保留的模型数据CSV文件 + if os.path.exists(file_path): + df = pd.read_csv(file_path) + if not df.empty and self.holddata==True: + # 选择最后一行数据 + row = df.iloc[-1] + # 根据CSV文件的列名将数据赋值给相应的属性 + self.pos = int(row['pos']) + self.short_trailing_stop_price = float(row['short_trailing_stop_price']) + self.long_trailing_stop_price = float(row['long_trailing_stop_price']) + self.sl_long_price = float(row['sl_long_price']) + self.sl_shor_price = float(row['sl_shor_price']) + # self.out_long = int(row['out_long']) + # self.out_short = int(row['out_short']) + print("找到历史交易数据文件,已经更新持仓,止损止盈数据", df.iloc[-1]) + self.holddata=False + else: + pass + #print("没有找到历史交易数据文件", file_path) + #如果没有找到CSV,则初始化变量 + + pass + + #保存数据 + def save_to_csv(self,symbol): + # 使用完整的合约代码 + symbol = str(symbol) + # 创建DataFrame + data = { + 'datetime': [datetime.now().strftime('%Y-%m-%d %H:%M:%S')], # 使用当前时间 + 'pos': [self.pos], + 'short_trailing_stop_price': [self.short_trailing_stop_price], + 'long_trailing_stop_price': [self.long_trailing_stop_price], + 'sl_long_price': [self.sl_long_price], + 'sl_shor_price': [self.sl_shor_price], + } + + df = pd.DataFrame(data) + + # 将DataFrame保存到CSV文件 + df.to_csv(f"traderdata/{symbol}traderdata.csv", index=False) + + #每日收盘重置数据 + def day_data_reset(self,data): + # 获取当前时间 + current_time = datetime.now().time() + + # 第一时间范围 + clearing_time1_start = s_time(14,55) + clearing_time1_end = s_time(15,00) + + # 第二时间范围 + clearing_time2_start = s_time(2,25) + clearing_time2_end = s_time(2,30) + + current_bid = float(data['BidPrice1']) # 当前买价 + current_ask = float(data['AskPrice1']) # 当前卖价 + + # 创建一个标志变量,用于记录是否已经执行过 + self.clearing_executed = False + # 检查当前时间第一个操作的时间范围内 + if clearing_time1_start <= current_time <= clearing_time1_end and not self.clearing_executed : + self.clearing_executed = True # 设置标志变量为已执行 + + # 如果有持仓,强制平仓 + if self.pos != 0: + print("交易日结束,开始强制平仓") + # 遍历所有合约发送平仓指令 + for instrument_id in list(self.stop_order_dict.keys()): + stops = self.stop_order_dict[instrument_id] + + # 平多仓 + if stops['long']['position'] > 0: + print(f"发送平多仓指令: {instrument_id}, 手数: {stops['long']['position']}, 价格: {current_bid}") + self.insert_order(data['ExchangeID'], data['InstrumentID'], + current_bid - self.py, + stops['long']['position'], + b'1', b'3') + # 平空仓 + if stops['short']['position'] > 0: + print(f"发送平空仓指令: {instrument_id}, 手数: {stops['short']['position']}, 价格: {current_ask}") + self.insert_order(data['ExchangeID'], data['InstrumentID'], + current_ask + self.py, + stops['short']['position'], + b'0', b'3') + + # 清空所有合约的持仓信息 + for instrument_id in list(self.stop_order_dict.keys()): + self.clear_position_info(instrument_id, 'all') + self.day_closed = True # 设置日内平仓标志 + print("日内交易已结束,禁止开新仓") + + # 检查当前时间是否在第二个操作的时间范围内 + elif clearing_time2_start <= current_time <= clearing_time2_end and not self.clearing_executed : + self.clearing_executed = True # 设置标志变量为已执行 + + # 如果有持仓,强制平仓 + if self.pos != 0: + print("交易日结束,开始强制平仓") + # 遍历所有合约发送平仓指令 + for instrument_id in list(self.stop_order_dict.keys()): + stops = self.stop_order_dict[instrument_id] + + # 平多仓 + if stops['long']['position'] > 0: + print(f"发送平多仓指令: {instrument_id}, 手数: {stops['long']['position']}, 价格: {current_bid}") + self.insert_order(data['ExchangeID'], data['InstrumentID'], + current_bid - self.py, + stops['long']['position'], + b'1', b'3') + # 平空仓 + if stops['short']['position'] > 0: + print(f"发送平空仓指令: {instrument_id}, 手数: {stops['short']['position']}, 价格: {current_ask}") + self.insert_order(data['ExchangeID'], data['InstrumentID'], + current_ask + self.py, + stops['short']['position'], + b'0', b'3') + + # 清空所有合约的持仓信息 + for instrument_id in list(self.stop_order_dict.keys()): + self.clear_position_info(instrument_id, 'all') + self.day_closed = True # 设置日内平仓标志 + print("日内交易已结束,禁止开新仓") + else: + self.clearing_executed = False + # 在新交易日开始时重置日内平仓标志 + if current_time < clearing_time1_start or (current_time > clearing_time1_end and current_time < clearing_time2_start): + self.day_closed = False + return self.clearing_executed + + def OnRtnTrade(self, pTrade): + print("||成交回报||", pTrade) + + # 获取成交信息 + instrument_id = pTrade['InstrumentID'].decode() + direction = pTrade['Direction'].decode() # '0'为买入,'1'为卖出 + offset_flag = pTrade['OffsetFlag'].decode() # '0'为开仓,'1'为平仓,'3'为平今 + volume = pTrade['Volume'] + price = pTrade['Price'] + + # 根据成交类型更新持仓信息 + if offset_flag in ['1', '3']: # 平仓或平今 + # 判断平的是多头还是空头 + if direction == '1': # 卖出,平多头 + print(f"平多头成交: {instrument_id}, 价格: {price}, 数量: {volume}") + # 清空多头持仓信息 + self.clear_position_info(instrument_id, 'long') + else: # 买入,平空头 + print(f"平空头成交: {instrument_id}, 价格: {price}, 数量: {volume}") + # 清空空头持仓信息 + self.clear_position_info(instrument_id, 'short') + + elif offset_flag == '0': # 开仓 + if direction == '0': # 买入,开多头 + print(f"开多头成交: {instrument_id}, 价格: {price}, 数量: {volume}") + # 如果有空头持仓,先清空 + if instrument_id in self.stop_order_dict and self.stop_order_dict[instrument_id]['short']['position'] > 0: + self.clear_position_info(instrument_id, 'short') + + # 设置多头持仓信息 + sl_price = price * (1 - self.fixed_stop_loss_percent) # 默认止损价 + tp_price = price * (1 + self.trailing_stop_percent) # 默认止盈价 + + # 设置初始跟踪止损价,与开仓价保持一定距离 + initial_trailing_stop = price * (1 - self.trailing_stop_percent) + + log_message = f"设置止损价: {sl_price}, 止盈价: {tp_price}, 跟踪止损价: {initial_trailing_stop}, 跟踪百分比: {self.trailing_stop_percent*100:.3f}%" + STOPLOSS_LOGGER.info(log_message) + + # 更新多头持仓信息,设置合理的跟踪止损初始值 + self.update_stop_order_dict(instrument_id, 'long', volume, price, sl_price, tp_price, initial_trailing_stop) + self.pos = volume # 更新全局持仓状态 + + # 兼容旧代码 + self.long_trailing_stop_price = initial_trailing_stop + self.sl_long_price = sl_price + self.save_to_csv(instrument_id) + + else: # 卖出,开空头 + print(f"开空头成交: {instrument_id}, 价格: {price}, 数量: {volume}") + # 如果有多头持仓,先清空 + if instrument_id in self.stop_order_dict and self.stop_order_dict[instrument_id]['long']['position'] > 0: + self.clear_position_info(instrument_id, 'long') + + # 设置空头持仓信息 + sl_price = price * (1 + self.fixed_stop_loss_percent) # 默认止损价 + tp_price = price * (1 - self.trailing_stop_percent) # 默认止盈价 + + # 设置初始跟踪止损价,与开仓价保持一定距离 + initial_trailing_stop = price * (1 + self.trailing_stop_percent) + + log_message = f"设置止损价: {sl_price}, 止盈价: {tp_price}, 跟踪止损价: {initial_trailing_stop}, 跟踪百分比: {self.trailing_stop_percent*100:.3f}%" + STOPLOSS_LOGGER.info(log_message) + + # 更新空头持仓信息,设置合理的跟踪止损初始值 + self.update_stop_order_dict(instrument_id, 'short', self.Lots, price, sl_price, tp_price, initial_trailing_stop) + self.pos = -1 # 更新全局持仓状态 + + # 兼容旧代码 + self.short_trailing_stop_price = initial_trailing_stop + self.sl_shor_price = sl_price + self.save_to_csv(instrument_id) + + def OnRspOrderInsert(self, pInputOrder, pRspInfo, nRequestID, bIsLast): + print("||OnRspOrderInsert||", pInputOrder, pRspInfo, nRequestID, bIsLast) + + #公众号:松鼠Quant + #主页:www.quant789.com + #本策略仅作学习交流使用,实盘交易盈亏投资者个人负责!!! + #版权归松鼠Quant所有,禁止转发、转卖源码违者必究。 + + #注意:运行前请先安装好algoplus, + # pip install AlgoPlus + #http://www.algo.plus/ctp/python/0103001.html + + # 订单状态通知 + def OnRtnOrder(self, pOrder): + print("||订单回报||", pOrder) + + def Join(self): + data = None + # 记录上次加载止盈止损信息的时间和合约 + last_load_time = {} + + while True: + if self.status == 0: + + while not self.md_queue.empty(): + data = self.md_queue.get(block=False) + instrument_id = data['InstrumentID'].decode() # 品种代码 + + # 首次运行时加载历史数据 + if self.kgdata: + self.load_history_data(instrument_id) + self.kgdata = False + + # 加载该合约的止盈止损信息,避免频繁加载 + current_time = time.time() + if instrument_id not in last_load_time or current_time - last_load_time.get(instrument_id, 0) > 60: # 每60秒才重新加载一次 + self.load_stop_orders_from_file(instrument_id) + last_load_time[instrument_id] = current_time + + # 检查止盈止损条件 + self.check_stop_conditions(data) + + # 在每个tick都检查和处理AI交易信号 - 移到这里以提高执行速度 + if self.use_ai_model: + self.check_and_process_ai_signals(data) + + # 原有代码... + self.read_to_csv(instrument_id) + self.day_data_reset(data) + tickcome(data) + #新K线开始,启动交易程序 and 保存行情数据 + if len(trader_df)>self.cont_df and len(trader_df)>0: + # 计算日均线 + trader_df['dayma'] = trader_df['close'].mean() + + # 计算累积的delta值 + trader_df['delta'] = trader_df['delta'].astype(float) + trader_df['delta累计'] = trader_df['delta'].cumsum() + + # 检查文件是否存在 + json_file_path = f"traderdata/{instrument_id}_ofdata.json" + + # 确保待保存的新数据中datetime字段是格式化的日期时间字符串 + if 'datetime' in trader_df.columns: + # 无论什么类型,都统一转换为字符串格式 + trader_df['datetime'] = trader_df['datetime'].astype(str) + + if os.path.exists(json_file_path): + try: + # 读取现有数据 + existing_df = pd.read_json(json_file_path, lines=True) + + # 确保现有数据中的datetime字段是字符串类型 + if 'datetime' in existing_df.columns: + existing_df['datetime'] = existing_df['datetime'].astype(str) + + # 合并新数据 + combined_df = pd.concat([existing_df, trader_df.tail(1)], ignore_index=True) + # 保存合并后的数据,使用lines=True确保每行是独立的JSON对象 + combined_df.to_json(json_file_path, orient='records', force_ascii=False, lines=True) + except Exception as e: + print(f"读取或保存JSON文件时出错: {e}") + # 如果读取出错,直接保存当前数据 + trader_df.to_json(json_file_path, orient='records', force_ascii=False, lines=True) + else: + # 创建新文件并保存整个DataFrame + trader_df.to_json(json_file_path, orient='records', force_ascii=False, lines=True) + + # 更新跟踪止损价格 - 兼容旧版本代码 + if self.long_trailing_stop_price >0 and self.pos>0: + self.long_trailing_stop_price = trader_df['low'].iloc[-1] if self.long_trailing_stop_price0 and self.pos<0: + self.short_trailing_stop_price = trader_df['high'].iloc[-1] if trader_df['high'].iloc[-1] self.trader_rows: + AI_THREAD_RUNNING = True + ai_thread = threading.Thread( + target=self.background_model_call, + args=(trader_df, instrument_id) + ) + ai_thread.daemon = True # 设置为守护线程,主程序退出时自动结束 + ai_thread.start() + print("启动AI分析线程...") + + print(trader_df['datetime']) + self.cont_df=len(trader_df) + else: + time.sleep(1) + + def background_model_call(self, data_df, instrument_id): + """ + 在后台线程中调用大模型,并将交易信号放入队列 + + Args: + data_df: 包含订单流数据的DataFrame + instrument_id: 合约ID + """ + global AI_THREAD_RUNNING + + start_time = datetime.now() + log_message = f"\n===== 开始AI分析 [{start_time.strftime('%Y-%m-%d %H:%M:%S')}] =====" + print(log_message) + AI_LOGGER.info(log_message) + + log_message = f"正在分析合约: {instrument_id}" + print(log_message) + AI_LOGGER.info(log_message) + + try: + # 复制DataFrame以避免在不同线程间共享数据可能导致的问题 + df_copy = data_df.copy() + + # 输出分析的数据行数 + log_message = f"分析数据行数: {len(df_copy)}" + print(log_message) + AI_LOGGER.info(log_message) + + log_message = f"最新价格: {df_copy['close'].iloc[-1] if len(df_copy) > 0 else 'N/A'}" + print(log_message) + AI_LOGGER.info(log_message) + + # 调用大模型获取交易信号 + trading_signal = call_deepseek_model(df_copy, self) # 传递self参数 + + # 计算分析耗时 + end_time = datetime.now() + elapsed = (end_time - start_time).total_seconds() + + # 将交易信号和合约ID一起放入队列 + signal_data = { + 'signal': trading_signal, + 'instrument_id': instrument_id, + 'timestamp': end_time # 使用结束时间作为时间戳 + } + + AI_SIGNAL_QUEUE.put(signal_data) + + log_message = f"AI模型分析完成,结果已放入队列,耗时: {elapsed:.2f}秒" + print(log_message) + AI_LOGGER.info(log_message) + + log_message = f"分析结果: {trading_signal}" + print(log_message) + AI_LOGGER.info(log_message) + + log_message = "===== AI分析完成 =====" + print(log_message + "\n") + AI_LOGGER.info(log_message) + except Exception as e: + end_time = datetime.now() + elapsed = (end_time - start_time).total_seconds() + + log_message = f"AI模型分析线程出现异常: {e}" + print(log_message) + AI_LOGGER.error(log_message) + + print(f"异常详情:") + import traceback + error_traceback = traceback.format_exc() + AI_LOGGER.error(f"异常详情:\n{error_traceback}") + traceback.print_exc() + + log_message = f"分析失败,耗时: {elapsed:.2f}秒" + print(log_message) + AI_LOGGER.error(log_message) + + log_message = "===== AI分析异常结束 =====" + print(log_message + "\n") + AI_LOGGER.error(log_message) + finally: + # 标记线程已完成 + AI_THREAD_RUNNING = False + + + #公众号:松鼠Quant + #主页:www.quant789.com + #本策略仅作学习交流使用,实盘交易盈亏投资者个人负责!!! + #版权归松鼠Quant所有,禁止转发、转卖源码违者必究。 + + #注意:运行前请先安装好algoplus, + # pip install AlgoPlus + #http://www.algo.plus/ctp/python/0103001.html + + def check_and_process_ai_signals(self, data): + """ + 检查并处理AI产生的交易信号 + 每个tick都会调用此函数,实现更快的交易信号响应 + """ + if AI_SIGNAL_QUEUE.empty(): + return + + # 从队列中获取信号 + signal_data = AI_SIGNAL_QUEUE.get() + trading_signal = signal_data['signal'] + instrument_id = signal_data['instrument_id'] + signal_time = signal_data['timestamp'] + + # 检查信号是否过期(超过15秒) + if (datetime.now() - signal_time).total_seconds() > 15: + log_message = f"AI信号已过期,忽略: {trading_signal}" + print(log_message) + SIGNAL_LOGGER.warning(log_message) + return + + # 验证合约ID是否匹配 + if instrument_id != data['InstrumentID'].decode(): + # 如果合约不匹配,将信号放回队列以便后续处理 + AI_SIGNAL_QUEUE.put(signal_data) + return + + log_message = f"\n===== 执行AI模型交易信号 [{datetime.now().strftime('%Y-%m-%d %H:%M:%S')}] =====" + print(log_message) + SIGNAL_LOGGER.info(log_message) + + log_message = f"信号生成时间: {signal_time.strftime('%Y-%m-%d %H:%M:%S')}" + print(log_message) + SIGNAL_LOGGER.info(log_message) + + log_message = f"信号类型: {trading_signal.get('action', '不操作')}" + print(log_message) + SIGNAL_LOGGER.info(log_message) + + log_message = f"置信度: {trading_signal.get('confidence', 0)}" + print(log_message) + SIGNAL_LOGGER.info(log_message) + + log_message = f"理由: {trading_signal.get('reason', '')}" + print(log_message) + SIGNAL_LOGGER.info(log_message) + + # 根据AI模型返回的交易信号执行交易 + action = trading_signal.get('action', '不操作') + confidence = trading_signal.get('confidence', 0) + reason = trading_signal.get('reason', '') + stop_loss = trading_signal.get('stop_loss', 0) + take_profit = trading_signal.get('take_profit', 0) + trailing_percent = trading_signal.get('trailing_percent', 0) + + # 如果AI建议了有效的跟踪止损百分比,则更新参数 + if 0.0001 <= trailing_percent <= 0.001: + old_percent = self.trailing_stop_percent + self.trailing_stop_percent = trailing_percent + log_message = f"更新跟踪止损百分比参数: {old_percent*100:.3f}% -> {trailing_percent*100:.3f}%" + STOPLOSS_LOGGER.info(log_message) + + # 获取现有持仓信息 + if instrument_id not in self.stop_order_dict: + self.stop_order_dict[instrument_id] = { + 'long': {'position': 0, 'entry_price': 0, 'stop_loss': 0, 'take_profit': 0, 'trailing_stop': 0}, + 'short': {'position': 0, 'entry_price': 0, 'stop_loss': 0, 'take_profit': 0, 'trailing_stop': 0} + } + + current_stops = self.stop_order_dict[instrument_id] + + # 如果持有多头或空头头寸,更新跟踪止损价 + if current_stops['long']['position'] > 0: + entry_price = current_stops['long']['entry_price'] + new_trailing_stop = float(data['BidPrice1']) * (1 - self.trailing_stop_percent) + old_trailing_stop = current_stops['long']['trailing_stop'] + + # 只有当新计算的跟踪止损价更高时才更新 + if new_trailing_stop > old_trailing_stop: + self.update_stop_order_dict(instrument_id, 'long', None, None, None, None, new_trailing_stop) + + # 兼容旧代码 + self.long_trailing_stop_price = new_trailing_stop + self.save_to_csv(instrument_id) + + elif current_stops['short']['position'] > 0: + entry_price = current_stops['short']['entry_price'] + new_trailing_stop = float(data['AskPrice1']) * (1 + self.trailing_stop_percent) + old_trailing_stop = current_stops['short']['trailing_stop'] + + # 只有当新计算的跟踪止损价更低或原来为0时才更新 + if new_trailing_stop < old_trailing_stop or old_trailing_stop == 0: + self.update_stop_order_dict(instrument_id, 'short', None, None, None, None, new_trailing_stop) + + # 兼容旧代码 + self.short_trailing_stop_price = new_trailing_stop + self.save_to_csv(instrument_id) + + # 只有当置信度大于等于5时才执行交易 + if confidence >= 6: + print(f"开始执行交易,当前价格: 买一{data['BidPrice1']} / 卖一{data['AskPrice1']}") + + # 获取现有持仓信息 + if instrument_id not in self.stop_order_dict: + self.stop_order_dict[instrument_id] = { + 'long': {'position': 0, 'entry_price': 0, 'stop_loss': 0, 'take_profit': 0, 'trailing_stop': 0}, + 'short': {'position': 0, 'entry_price': 0, 'stop_loss': 0, 'take_profit': 0, 'trailing_stop': 0} + } + + current_stops = self.stop_order_dict[instrument_id] + + if action == '开多' and current_stops['long']['position'] <= 0: + # 如果持有空头头寸,先平空 + if current_stops['short']['position'] > 0: + print('执行平空操作') + self.insert_order(data['ExchangeID'], data['InstrumentID'], + data['AskPrice1']+self.py, + current_stops['short']['position'], + b'0', b'3') + # 清空空头持仓信息 + self.clear_position_info(instrument_id, 'short') + + # 开多 + print('执行开多操作') + entry_price = float(data['AskPrice1']) + self.insert_order(data['ExchangeID'], data['InstrumentID'], + entry_price+self.py, self.Lots, b'0', b'0') + + # 使用AI建议的止损止盈价格 + sl_price = stop_loss if stop_loss > 0 else entry_price * (1 - self.fixed_stop_loss_percent) + tp_price = take_profit if take_profit > 0 else entry_price * (1 + self.trailing_stop_percent) + + # 设置初始跟踪止损价,与开仓价保持一定距离 + initial_trailing_stop = entry_price * (1 - self.trailing_stop_percent) + + log_message = f"设置止损价: {sl_price}, 止盈价: {tp_price}, 跟踪止损价: {initial_trailing_stop}, 跟踪百分比: {self.trailing_stop_percent*100:.3f}%" + STOPLOSS_LOGGER.info(log_message) + + # 更新多头持仓信息,设置合理的跟踪止损初始值 + self.update_stop_order_dict(instrument_id, 'long', self.Lots, entry_price, sl_price, tp_price, initial_trailing_stop) + self.pos = 1 # 更新全局持仓状态 + + # 兼容旧代码 + self.long_trailing_stop_price = initial_trailing_stop + self.sl_long_price = sl_price + self.save_to_csv(instrument_id) + + elif action == '开空' and current_stops['short']['position'] <= 0: + # 如果持有多头头寸,先平多 + if current_stops['long']['position'] > 0: + print('执行平多操作') + self.insert_order(data['ExchangeID'], data['InstrumentID'], + data['BidPrice1']-self.py, + current_stops['long']['position'], + b'1', b'3') + # 清空多头持仓信息 + self.clear_position_info(instrument_id, 'long') + + # 开空 + print('执行开空操作') + entry_price = float(data['BidPrice1']) + self.insert_order(data['ExchangeID'], data['InstrumentID'], + entry_price-self.py, self.Lots, b'1', b'0') + + # 使用AI建议的止损止盈价格 + sl_price = stop_loss if stop_loss > 0 else entry_price * (1 + self.fixed_stop_loss_percent) + tp_price = take_profit if take_profit > 0 else entry_price * (1 - self.trailing_stop_percent) + + # 设置初始跟踪止损价,与开仓价保持一定距离 + initial_trailing_stop = entry_price * (1 + self.trailing_stop_percent) + + log_message = f"设置止损价: {sl_price}, 止盈价: {tp_price}, 跟踪止损价: {initial_trailing_stop}, 跟踪百分比: {self.trailing_stop_percent*100:.3f}%" + STOPLOSS_LOGGER.info(log_message) + + # 更新空头持仓信息,设置合理的跟踪止损初始值 + self.update_stop_order_dict(instrument_id, 'short', self.Lots, entry_price, sl_price, tp_price, initial_trailing_stop) + self.pos = -1 # 更新全局持仓状态 + + # 兼容旧代码 + self.short_trailing_stop_price = initial_trailing_stop + self.sl_shor_price = sl_price + self.save_to_csv(instrument_id) + + elif action == '平多' and current_stops['long']['position'] > 0: + print('执行平多操作') + self.insert_order(data['ExchangeID'], data['InstrumentID'], + data['BidPrice1']-self.py, + current_stops['long']['position'], + b'1', b'3') + # 清空多头持仓信息 + self.clear_position_info(instrument_id, 'long') + + elif action == '平空' and current_stops['short']['position'] > 0: + print('执行平空操作') + self.insert_order(data['ExchangeID'], data['InstrumentID'], + data['AskPrice1']+self.py, + current_stops['short']['position'], + b'0', b'3') + # 清空空头持仓信息 + self.clear_position_info(instrument_id, 'short') + + # 添加处理复合交易指令的逻辑 - 平多开空 + elif action == '平多开空' and current_stops['long']['position'] > 0: + print('执行平多开空操作') + + # 第一步:平多 + print('1. 执行平多操作') + self.insert_order(data['ExchangeID'], data['InstrumentID'], + data['BidPrice1']-self.py, + current_stops['long']['position'], + b'1', b'3') + # 清空多头持仓信息 + self.clear_position_info(instrument_id, 'long') + + # 第二步:开空 + print('2. 执行开空操作') + entry_price = float(data['BidPrice1']) + self.insert_order(data['ExchangeID'], data['InstrumentID'], + entry_price-self.py, self.Lots, b'1', b'0') + + # 使用AI建议的止损止盈价格 + sl_price = stop_loss if stop_loss > 0 else entry_price * (1 + self.fixed_stop_loss_percent) + tp_price = take_profit if take_profit > 0 else entry_price * (1 - self.trailing_stop_percent) + + # 设置初始跟踪止损价,与开仓价保持一定距离 + initial_trailing_stop = entry_price * (1 + self.trailing_stop_percent) + + log_message = f"设置止损价: {sl_price}, 止盈价: {tp_price}, 跟踪止损价: {initial_trailing_stop}, 跟踪百分比: {self.trailing_stop_percent*100:.3f}%" + STOPLOSS_LOGGER.info(log_message) + + # 更新空头持仓信息 + self.update_stop_order_dict(instrument_id, 'short', self.Lots, entry_price, sl_price, tp_price, initial_trailing_stop) + self.pos = -1 # 更新全局持仓状态 + + # 兼容旧代码 + self.short_trailing_stop_price = initial_trailing_stop + self.sl_shor_price = sl_price + self.save_to_csv(instrument_id) + + # 添加处理复合交易指令的逻辑 - 平空开多 + elif action == '平空开多' and current_stops['short']['position'] > 0: + print('执行平空开多操作') + + # 第一步:平空 + print('1. 执行平空操作') + self.insert_order(data['ExchangeID'], data['InstrumentID'], + data['AskPrice1']+self.py, + current_stops['short']['position'], + b'0', b'3') + # 清空空头持仓信息 + self.clear_position_info(instrument_id, 'short') + + # 第二步:开多 + print('2. 执行开多操作') + entry_price = float(data['AskPrice1']) + self.insert_order(data['ExchangeID'], data['InstrumentID'], + entry_price+self.py, self.Lots, b'0', b'0') + + # 使用AI建议的止损止盈价格 + sl_price = stop_loss if stop_loss > 0 else entry_price * (1 - self.fixed_stop_loss_percent) + tp_price = take_profit if take_profit > 0 else entry_price * (1 + self.trailing_stop_percent) + + # 设置初始跟踪止损价,与开仓价保持一定距离 + initial_trailing_stop = entry_price * (1 - self.trailing_stop_percent) + + log_message = f"设置止损价: {sl_price}, 止盈价: {tp_price}, 跟踪止损价: {initial_trailing_stop}, 跟踪百分比: {self.trailing_stop_percent*100:.3f}%" + STOPLOSS_LOGGER.info(log_message) + + # 更新多头持仓信息 + self.update_stop_order_dict(instrument_id, 'long', self.Lots, entry_price, sl_price, tp_price, initial_trailing_stop) + self.pos = 1 # 更新全局持仓状态 + + # 兼容旧代码 + self.long_trailing_stop_price = initial_trailing_stop + self.sl_long_price = sl_price + self.save_to_csv(instrument_id) + + # 如果AI建议调整止损止盈价格 + elif action == '不操作': + if stop_loss > 0: + if current_stops['long']['position'] > 0: # 多头持仓 + self.update_stop_order_dict(instrument_id, 'long', None, None, stop_loss, None, None) + print(f'已调整多头止损价: {stop_loss}') + + # 兼容旧代码 + self.sl_long_price = stop_loss + self.save_to_csv(instrument_id) + elif current_stops['short']['position'] > 0: # 空头持仓 + self.update_stop_order_dict(instrument_id, 'short', None, None, stop_loss, None, None) + print(f'已调整空头止损价: {stop_loss}') + + # 兼容旧代码 + self.sl_shor_price = stop_loss + self.save_to_csv(instrument_id) + + if take_profit > 0: + if current_stops['long']['position'] > 0: # 多头持仓 + self.update_stop_order_dict(instrument_id, 'long', None, None, None, take_profit, None) + print(f'已调整多头止盈价: {take_profit}') + + # 兼容旧代码 + self.long_trailing_stop_price = take_profit + self.save_to_csv(instrument_id) + elif current_stops['short']['position'] > 0: # 空头持仓 + self.update_stop_order_dict(instrument_id, 'short', None, None, None, take_profit, None) + print(f'已调整空头止盈价: {take_profit}') + + # 兼容旧代码 + self.short_trailing_stop_price = take_profit + self.save_to_csv(instrument_id) + + print("===== 交易信号执行完成 =====\n") + else: + print(f"信号置信度{confidence}低于执行阈值(5),不执行交易") + print("===== 交易信号处理完成 =====\n") + + #公众号:松鼠Quant + #主页:www.quant789.com + #本策略仅作学习交流使用,实盘交易盈亏投资者个人负责!!! + #版权归松鼠Quant所有,禁止转发、转卖源码违者必究。 + + #注意:运行前请先安装好algoplus, + # pip install AlgoPlus + #http://www.algo.plus/ctp/python/0103001.html + + def format_data_for_llm(self, df): + """ + 将DataFrame格式化为适合LLM分析的文本格式,包含历史交易信息 + """ + # 提取最近几条记录 + recent_data = df.tail(self.trader_rows) + + # 构建基本信息 + data_text = "订单流数据分析:\n\n" + + # 提取最新行情数据 + instrument_id = recent_data['symbol'].iloc[-1] + + # 添加最新价格和交易量信息 + data_text += f"当前时间: {recent_data['datetime'].iloc[-1]}\n" + data_text += f"当前价格: {recent_data['close'].iloc[-1]}\n" + data_text += f"开盘价: {recent_data['open'].iloc[-1]}\n" + data_text += f"最高价: {recent_data['high'].iloc[-1]}\n" + data_text += f"最低价: {recent_data['low'].iloc[-1]}\n" + data_text += f"成交量: {recent_data['volume'].iloc[-1]}\n" + + # 计算价格趋势 + if len(recent_data) >= 5: + price_trend = recent_data['close'].pct_change().tail(5).mean() * 100 + data_text += f"价格短期趋势: {'上涨' if price_trend > 0 else '下跌'} ({price_trend:.2f}%)\n" + + # 计算价格波动性 + if len(recent_data) >= 5: + volatility = recent_data['close'].pct_change().tail(5).std() * 100 + data_text += f"价格波动性: {volatility:.2f}%\n" + + # 添加支撑和阻力位分析 + recent_high = recent_data['high'].max() + recent_low = recent_data['low'].min() + data_text += f"近期阻力位: {recent_high}\n" + data_text += f"近期支撑位: {recent_low}\n" + + # 添加均线分析 - 计算5、10、20均线 + if len(df) >= 20: + # 计算均线 + ma5 = df['close'].rolling(5).mean().iloc[-1] + ma10 = df['close'].rolling(10).mean().iloc[-1] + ma20 = df['close'].rolling(20).mean().iloc[-1] + + data_text += f"MA5: {ma5:.2f}\n" + data_text += f"MA10: {ma10:.2f}\n" + data_text += f"MA20: {ma20:.2f}\n" + + # 判断均线形态 + if abs(ma5 - ma10) / ma10 < 0.001 and abs(ma10 - ma20) / ma20 < 0.001: + ma_pattern = "均线粘合" + elif ma5 > ma10 and ma10 > ma20: + ma_pattern = "多头排列" + elif ma5 < ma10 and ma10 < ma20: + ma_pattern = "空头排列" + elif ma5 > ma10 and ma10 < ma20: + ma_pattern = "金叉形态" + elif ma5 < ma10 and ma10 > ma20: + ma_pattern = "死叉形态" + else: + ma_pattern = "无明显形态" + + data_text += f"均线形态: {ma_pattern}\n" + + # 价格与均线关系 + current_price = df['close'].iloc[-1] + data_text += f"价格相对MA5: {'上方' if current_price > ma5 else '下方'} ({(current_price/ma5-1)*100:.2f}%)\n" + data_text += f"价格相对MA10: {'上方' if current_price > ma10 else '下方'} ({(current_price/ma10-1)*100:.2f}%)\n" + data_text += f"价格相对MA20: {'上方' if current_price > ma20 else '下方'} ({(current_price/ma20-1)*100:.2f}%)\n" + + # 日内超涨超跌分析 + if len(df) >= 20: + # 计算日内振幅 + daily_high = df['high'].iloc[-20:].max() + daily_low = df['low'].iloc[-20:].min() + daily_range = (daily_high - daily_low) / daily_low * 100 + + # 当前价格在日内范围的位置 + current_in_range = (df['close'].iloc[-1] - daily_low) / (daily_high - daily_low) * 100 if (daily_high - daily_low) > 0 else 50 + + data_text += f"日内振幅: {daily_range:.2f}%\n" + data_text += f"价格在日内范围的位置: {current_in_range:.2f}% (0%为日低, 100%为日高)\n" + + # 判断超涨超跌 + if current_in_range > 85: + data_text += "日内状态: 可能超涨\n" + elif current_in_range < 15: + data_text += "日内状态: 可能超跌\n" + else: + data_text += "日内状态: 正常区间\n" + + # 形态识别 + if len(df) >= 20: + # 简单K线形态识别 + recent_k = df.tail(5).copy() + + # 计算实体和影线 + recent_k['body'] = abs(recent_k['close'] - recent_k['open']) + recent_k['upper_shadow'] = recent_k.apply(lambda x: x['high'] - max(x['open'], x['close']), axis=1) + recent_k['lower_shadow'] = recent_k.apply(lambda x: min(x['open'], x['close']) - x['low'], axis=1) + + # 最新K线特征 + latest_k = recent_k.iloc[-1] + prev_k = recent_k.iloc[-2] if len(recent_k) > 1 else None + + data_text += "\nK线形态分析:\n" + + # 判断最新K线类型 + if latest_k['body'] == 0: + k_type = "十字星" + elif latest_k['upper_shadow'] > 2 * latest_k['body'] and latest_k['lower_shadow'] < 0.5 * latest_k['body']: + k_type = "上影线长" + elif latest_k['lower_shadow'] > 2 * latest_k['body'] and latest_k['upper_shadow'] < 0.5 * latest_k['body']: + k_type = "下影线长" + elif latest_k['close'] > latest_k['open'] and latest_k['body'] > np.mean(recent_k['body']): + k_type = "大阳线" + elif latest_k['close'] < latest_k['open'] and latest_k['body'] > np.mean(recent_k['body']): + k_type = "大阴线" + elif latest_k['close'] > latest_k['open']: + k_type = "小阳线" + elif latest_k['close'] < latest_k['open']: + k_type = "小阴线" + else: + k_type = "普通K线" + + data_text += f"最新K线类型: {k_type}\n" + + # 判断简单组合形态 + if prev_k is not None: + if prev_k['close'] < prev_k['open'] and latest_k['close'] > latest_k['open'] and latest_k['open'] <= prev_k['close'] and latest_k['close'] > prev_k['open']: + data_text += "组合形态: 可能构成看涨吞没形态\n" + elif prev_k['close'] > prev_k['open'] and latest_k['close'] < latest_k['open'] and latest_k['open'] >= prev_k['close'] and latest_k['close'] < prev_k['open']: + data_text += "组合形态: 可能构成看跌吞没形态\n" + elif prev_k['close'] < prev_k['open'] and latest_k['close'] > latest_k['open'] and latest_k['body'] > 1.5 * prev_k['body']: + data_text += "组合形态: 可能构成看涨势能增强\n" + elif prev_k['close'] > prev_k['open'] and latest_k['close'] < latest_k['open'] and latest_k['body'] > 1.5 * prev_k['body']: + data_text += "组合形态: 可能构成看跌势能增强\n" + + # 添加订单流特定数据 + data_text += f"\n订单流净值: {recent_data['delta'].iloc[-1]}\n" + data_text += f"订单流累计值: {recent_data['delta累计'].iloc[-1] if 'delta累计' in recent_data.columns else '无数据'}\n" + data_text += f"堆积指标: {recent_data['dj'].iloc[-1]}\n" + + # 添加日均线数据 + data_text += f"日均线: {recent_data['dayma'].iloc[-1] if 'dayma' in recent_data.columns else '无数据'}\n" + + # 添加价格与日均线的关系 + if 'dayma' in recent_data.columns: + price_above_ma = recent_data['close'].iloc[-1] > recent_data['dayma'].iloc[-1] + data_text += f"价格位于日均线: {'上方' if price_above_ma else '下方'}\n" + + # 订单流全面分析 + data_text += "\n订单流详细分析:\n" + + # 计算订单流趋势 + if len(recent_data) >= 5: + delta_values = recent_data['delta'].values + delta_trend = np.mean(np.diff(delta_values)) if len(delta_values) > 1 else 0 + data_text += f"订单流趋势: {'增强中' if delta_trend > 0 else '减弱中'} (变化率: {delta_trend:.2f})\n" + + # 计算订单流强度(使用绝对值的平均值) + delta_strength = np.mean(np.abs(recent_data['delta'].values)) + data_text += f"订单流强度: {delta_strength:.2f}\n" + + # 订单流指标超涨超跌分析 + if len(df) >= 20: + delta_values = df['delta'].iloc[-20:].values + delta_mean = np.mean(delta_values) + delta_std = np.std(delta_values) + current_delta = df['delta'].iloc[-1] + + # Z分数计算 + if delta_std > 0: + delta_z = (current_delta - delta_mean) / delta_std + data_text += f"订单流偏离度(Z分数): {delta_z:.2f}\n" + + if delta_z > 2: + data_text += "订单流状态: 可能超买\n" + elif delta_z < -2: + data_text += "订单流状态: 可能超卖\n" + else: + data_text += "订单流状态: 正常区间\n" + + # 买卖力量对比 + if 'bid_v' in recent_data.columns and 'ask_v' in recent_data.columns: + bid_power = recent_data['bid_v'].mean() + ask_power = recent_data['ask_v'].mean() + power_ratio = bid_power / ask_power if ask_power != 0 else float('inf') + data_text += f"买卖比例: {power_ratio:.2f} (>1买方强势,<1卖方强势)\n" + + # 订单流累计趋势 + if 'delta累计' in recent_data.columns and len(recent_data) >= 2: + cumulative_start = recent_data['delta累计'].iloc[0] + cumulative_end = recent_data['delta累计'].iloc[-1] + cumulative_change = cumulative_end - cumulative_start + data_text += f"累计订单流变化: {cumulative_change:.2f} (从 {cumulative_start:.2f} 到 {cumulative_end:.2f})\n" + + # 订单流波动性 + delta_volatility = np.std(recent_data['delta'].values) + data_text += f"订单流波动性: {delta_volatility:.2f}\n" + + # 订单流与价格相关性 + if len(recent_data) >= 10: # 确保有足够数据计算相关性 + price_changes = recent_data['close'].pct_change().dropna() + delta_changes = recent_data['delta'].iloc[1:].reset_index(drop=True) # 对齐索引 + if len(price_changes) > 0 and len(delta_changes) == len(price_changes): + try: + correlation = np.corrcoef(price_changes, delta_changes)[0, 1] if len(price_changes) > 1 else 0 + data_text += f"订单流与价格相关性: {correlation:.2f}\n" + data_text += f"相关性解读: {'强正相关' if correlation > 0.7 else '正相关' if correlation > 0.3 else '弱相关' if correlation > -0.3 else '负相关' if correlation > -0.7 else '强负相关'}\n" + except: + data_text += "订单流与价格相关性: 计算错误\n" + + # 订单流势能分析(最近几分钟的方向) + recent_deltas = recent_data['delta'].tail(5).values + positive_count = sum(1 for x in recent_deltas if x > 0) + negative_count = sum(1 for x in recent_deltas if x < 0) + data_text += f"最近订单流方向: {'多头主导' if positive_count > negative_count else '空头主导' if positive_count < negative_count else '方向不明'} ({positive_count}正/{negative_count}负)\n" + + # 订单流强弱可视化 + delta_last_5 = recent_data['delta'].tail(5).values + strength_visual = "" + for val in delta_last_5: + if val > 3: + strength_visual += "↑↑ " + elif val > 0: + strength_visual += "↑ " + elif val < -3: + strength_visual += "↓↓ " + elif val < 0: + strength_visual += "↓ " + else: + strength_visual += "→ " + data_text += f"订单流强弱可视化 (最近5分钟): {strength_visual}\n" + + # 添加最近几条记录的趋势 + data_text += "\n最近几条记录的趋势:\n" + + # 添加最近5条记录的关键指标变化 + for i in range(min(5, len(recent_data))): + idx = -(i+1) + data_text += f"记录 {i+1}: 时间={recent_data['datetime'].iloc[idx]}, 价格={recent_data['close'].iloc[idx]}, " + data_text += f"订单流净值={recent_data['delta'].iloc[idx]}, 堆积={recent_data['dj'].iloc[idx]}\n" + + # 添加当前持仓信息,使用新的止盈止损字典 + data_text += "\n当前持仓状态:\n" + + # 获取该合约的止盈止损信息 + stops = self.stop_order_dict.get(instrument_id, { + 'long': {'position': 0, 'entry_price': 0, 'stop_loss': 0, 'take_profit': 0, 'trailing_stop': 0}, + 'short': {'position': 0, 'entry_price': 0, 'stop_loss': 0, 'take_profit': 0, 'trailing_stop': 0} + }) + + # 获取多头和空头持仓信息 + long_pos = stops.get('long', {}).get('position', 0) + short_pos = stops.get('short', {}).get('position', 0) + + # 判断当前持仓方向 + if long_pos > 0: + data_text += f"持仓方向: 多头\n" + data_text += f"持仓数量: {long_pos}\n" + data_text += f"开仓价格: {stops['long']['entry_price']}\n" + data_text += f"止损价格: {stops['long']['stop_loss']}\n" + data_text += f"止盈价格: {stops['long']['take_profit']}\n" + data_text += f"跟踪止损价: {stops['long']['trailing_stop']}\n" + + # 计算当前盈亏 + current_price = recent_data['close'].iloc[-1] + profit_percent = (current_price - stops['long']['entry_price']) / stops['long']['entry_price'] * 100 + data_text += f"当前盈亏: {profit_percent:.2f}%\n" + elif short_pos > 0: + data_text += f"持仓方向: 空头\n" + data_text += f"持仓数量: {short_pos}\n" + data_text += f"开仓价格: {stops['short']['entry_price']}\n" + data_text += f"止损价格: {stops['short']['stop_loss']}\n" + data_text += f"止盈价格: {stops['short']['take_profit']}\n" + data_text += f"跟踪止损价: {stops['short']['trailing_stop']}\n" + + # 计算当前盈亏 + current_price = recent_data['close'].iloc[-1] + profit_percent = (stops['short']['entry_price'] - current_price) / stops['short']['entry_price'] * 100 + data_text += f"当前盈亏: {profit_percent:.2f}%\n" + else: + data_text += "持仓方向: 空仓\n" + data_text += "持仓数量: 0\n" + + # 添加风险管理参数信息 + data_text += "\n风险管理参数设置:\n" + data_text += f"固定止损百分比: {self.fixed_stop_loss_percent * 100:.2f}%\n" + data_text += f"跟踪止损百分比: {self.trailing_stop_percent * 100:.2f}%\n" + + # 添加交易建议提示 + data_text += "\n请根据以上信息,分析当前市场状态并给出交易建议。需要考虑:\n" + data_text += "1. 当前持仓状态是否合理\n" + data_text += "2. 是否需要调整止损止盈位置\n" + data_text += "3. 是否需要平仓或反手\n" + data_text += "4. 是否适合开新仓\n" + data_text += "5. 是否需要调整跟踪止损百分比参数(范围建议:0.0001-0.001)\n" + data_text += "6. 是否出现抄底摸顶机会\n" + data_text += "7. 是否存在日内波段交易机会\n" + + return data_text + + def update_stop_order_dict(self, instrument_id, direction, position, entry_price=None, stop_loss=None, take_profit=None, trailing_stop=None): + """更新止损止盈信息""" + # 初始化合约的止损止盈字典 + if instrument_id not in self.stop_order_dict: + self.stop_order_dict[instrument_id] = { + 'long': {'position': 0, 'entry_price': 0, 'stop_loss': 0, 'take_profit': 0, 'trailing_stop': 0}, + 'short': {'position': 0, 'entry_price': 0, 'stop_loss': 0, 'take_profit': 0, 'trailing_stop': 0} + } + + # 获取当前值 + current_values = self.stop_order_dict[instrument_id][direction].copy() + + # 更新值 + if position is not None: + self.stop_order_dict[instrument_id][direction]['position'] = position + if entry_price is not None: + self.stop_order_dict[instrument_id][direction]['entry_price'] = entry_price + if stop_loss is not None: + self.stop_order_dict[instrument_id][direction]['stop_loss'] = stop_loss + if take_profit is not None: + self.stop_order_dict[instrument_id][direction]['take_profit'] = take_profit + if trailing_stop is not None: + self.stop_order_dict[instrument_id][direction]['trailing_stop'] = trailing_stop + + # 记录变化值 + updated_values = self.stop_order_dict[instrument_id][direction] + change_log = f"更新{instrument_id} {direction}头寸止损止盈: " + changes = [] + + if position is not None and position != current_values['position']: + changes.append(f"仓位: {current_values['position']} -> {position}") + if entry_price is not None and entry_price != current_values['entry_price']: + changes.append(f"入场价: {current_values['entry_price']} -> {entry_price}") + if stop_loss is not None and stop_loss != current_values['stop_loss']: + changes.append(f"止损价: {current_values['stop_loss']} -> {stop_loss}") + if take_profit is not None and take_profit != current_values['take_profit']: + changes.append(f"止盈价: {current_values['take_profit']} -> {take_profit}") + if trailing_stop is not None and trailing_stop != current_values['trailing_stop']: + changes.append(f"跟踪止损价: {current_values['trailing_stop']} -> {trailing_stop}") + + if changes: + change_log += ", ".join(changes) + STOPLOSS_LOGGER.info(change_log) + + # 保存到文件 + self.save_stop_orders_to_file(instrument_id) + + def save_stop_orders_to_file(self, instrument_id): + """将止盈止损信息保存到文件""" + # 使用完整的合约代码 + symbol = str(instrument_id) + folder_path = "traderdata" + file_path = os.path.join(folder_path, f"{symbol}_stops.json") + + # 如果文件夹不存在则创建 + if not os.path.exists(folder_path): + os.makedirs(folder_path) + + # 保存字典到JSON文件 + with open(file_path, 'w') as f: + json.dump(self.stop_order_dict.get(instrument_id, {}), f, indent=4) + + # 获取该合约的止盈止损信息 + stops = self.stop_order_dict.get(instrument_id, { + 'long': {'position': 0, 'entry_price': 0, 'stop_loss': 0, 'take_profit': 0, 'trailing_stop': 0}, + 'short': {'position': 0, 'entry_price': 0, 'stop_loss': 0, 'take_profit': 0, 'trailing_stop': 0} + }) + + # 打印详细信息 + print(f"\n===== 已更新止盈止损信息: {instrument_id} =====") + print(f"多头持仓: {stops['long']['position']} 手") + print(f"多头入场价: {stops['long']['entry_price']}") + print(f"多头止损价: {stops['long']['stop_loss']}") + print(f"多头止盈价: {stops['long']['take_profit']}") + print(f"多头跟踪止损: {stops['long']['trailing_stop']}") + print(f"空头持仓: {stops['short']['position']} 手") + print(f"空头入场价: {stops['short']['entry_price']}") + print(f"空头止损价: {stops['short']['stop_loss']}") + print(f"空头止盈价: {stops['short']['take_profit']}") + print(f"空头跟踪止损: {stops['short']['trailing_stop']}") + print("======================================\n") + + def load_stop_orders_from_file(self, instrument_id): + """从文件加载止盈止损信息""" + # 如果合约ID已经在字典中,直接返回,避免重复加载 + if instrument_id in self.stop_order_dict: + return True + + # 使用完整的合约代码 + symbol = str(instrument_id) + folder_path = "traderdata" + file_path = os.path.join(folder_path, f"{symbol}_stops.json") + + if os.path.exists(file_path): + try: + with open(file_path, 'r') as f: + stops_data = json.load(f) + + # 更新字典 + self.stop_order_dict[instrument_id] = stops_data + print(f"首次加载止盈止损信息: {instrument_id}") + return True + except Exception as e: + print(f"加载止盈止损信息失败: {e}") + + # 如果文件不存在,初始化空字典结构 + if instrument_id not in self.stop_order_dict: + self.stop_order_dict[instrument_id] = { + 'long': {'position': 0, 'entry_price': 0, 'stop_loss': 0, 'take_profit': 0, 'trailing_stop': 0}, + 'short': {'position': 0, 'entry_price': 0, 'stop_loss': 0, 'take_profit': 0, 'trailing_stop': 0} + } + print(f"初始化止盈止损结构: {instrument_id}") + + return False + + def check_stop_conditions(self, data): + """检查是否满足止盈止损条件""" + instrument_id = data['InstrumentID'].decode() + + # 如果该合约不在止盈止损字典中,直接返回 + if instrument_id not in self.stop_order_dict: + return + + current_bid = float(data['BidPrice1']) # 当前买价 + current_ask = float(data['AskPrice1']) # 当前卖价 + + stops = self.stop_order_dict[instrument_id] + + # 检查多头止盈止损 + if stops['long']['position'] > 0: + entry_price = stops['long']['entry_price'] # 获取开仓价 + + # 检查止损 + if stops['long']['stop_loss'] > 0 and current_bid <= stops['long']['stop_loss']: + print(f"触发多头止损: {instrument_id}, 价格: {current_bid}, 止损价: {stops['long']['stop_loss']}") + self.insert_order(data['ExchangeID'], data['InstrumentID'], current_bid-self.py, + stops['long']['position'], b'1', b'3') + # 清空多头持仓信息 + self.clear_position_info(instrument_id, 'long') + self.pos = 0 # 更新全局持仓状态 + + # 检查跟踪止损 - 新增开仓价判断条件 + elif stops['long']['trailing_stop'] > 0 and current_bid < stops['long']['trailing_stop'] and current_bid > entry_price: + print(f"触发多头跟踪止损: {instrument_id}, 价格: {current_bid}, 跟踪止损价: {stops['long']['trailing_stop']}, 开仓价: {entry_price}") + self.insert_order(data['ExchangeID'], data['InstrumentID'], current_bid-self.py, + stops['long']['position'], b'1', b'3') + # 清空多头持仓信息 + self.clear_position_info(instrument_id, 'long') + self.pos = 0 # 更新全局持仓状态 + + # 检查止盈 + elif stops['long']['take_profit'] > 0 and current_bid >= stops['long']['take_profit']: + print(f"触发多头止盈: {instrument_id}, 价格: {current_bid}, 止盈价: {stops['long']['take_profit']}") + self.insert_order(data['ExchangeID'], data['InstrumentID'], current_bid-self.py, + stops['long']['position'], b'1', b'3') + # 清空多头持仓信息 + self.update_stop_order_dict(instrument_id, 'long', 0, 0, 0, 0) + self.pos = 0 # 更新全局持仓状态 + + # 更新跟踪止损价 - 只在价格上涨且大于开仓价时更新 + elif stops['long']['trailing_stop'] > 0 and current_bid > entry_price: + # 只有当前价格比之前设置的跟踪止损价高一定幅度时才更新 + new_trailing_stop = current_bid * (1 - self.trailing_stop_percent) + if new_trailing_stop > stops['long']['trailing_stop']: + self.update_stop_order_dict(instrument_id, 'long', None, None, None, None, new_trailing_stop) + print(f"更新多头跟踪止损: {instrument_id}, 新止损价: {new_trailing_stop}, 开仓价: {entry_price}") + + # 检查空头止盈止损 + if stops['short']['position'] > 0: + entry_price = stops['short']['entry_price'] # 获取开仓价 + + # 检查止损 + if stops['short']['stop_loss'] > 0 and current_ask >= stops['short']['stop_loss']: + print(f"触发空头止损: {instrument_id}, 价格: {current_ask}, 止损价: {stops['short']['stop_loss']}") + self.insert_order(data['ExchangeID'], data['InstrumentID'], current_ask+self.py, + stops['short']['position'], b'0', b'3') + # 清空空头持仓信息 + self.update_stop_order_dict(instrument_id, 'short', 0, 0, 0, 0, 0) + self.pos = 0 # 更新全局持仓状态 + + # 检查跟踪止损 - 新增开仓价判断条件 + elif stops['short']['trailing_stop'] > 0 and current_ask > stops['short']['trailing_stop'] and current_ask < entry_price: + print(f"触发空头跟踪止损: {instrument_id}, 价格: {current_ask}, 跟踪止损价: {stops['short']['trailing_stop']}, 开仓价: {entry_price}") + self.insert_order(data['ExchangeID'], data['InstrumentID'], current_ask+self.py, + stops['short']['position'], b'0', b'3') + # 清空空头持仓信息 + self.clear_position_info(instrument_id, 'short') + self.pos = 0 # 更新全局持仓状态 + + # 检查止盈 + elif stops['short']['take_profit'] > 0 and current_ask <= stops['short']['take_profit']: + print(f"触发空头止盈: {instrument_id}, 价格: {current_ask}, 止盈价: {stops['short']['take_profit']}") + self.insert_order(data['ExchangeID'], data['InstrumentID'], current_ask+self.py, + stops['short']['position'], b'0', b'3') + # 清空空头持仓信息 + self.update_stop_order_dict(instrument_id, 'short', 0, 0, 0, 0, 0) + self.pos = 0 # 更新全局持仓状态 + + # 更新跟踪止损价 - 只在价格下跌且小于开仓价时更新 + elif stops['short']['trailing_stop'] > 0 and current_ask < entry_price: + # 只有当前价格比之前设置的跟踪止损价低一定幅度时才更新 + new_trailing_stop = current_ask * (1 + self.trailing_stop_percent) + if new_trailing_stop < stops['short']['trailing_stop'] or stops['short']['trailing_stop'] == 0: + self.update_stop_order_dict(instrument_id, 'short', None, None, None, None, new_trailing_stop) + print(f"更新空头跟踪止损: {instrument_id}, 新止损价: {new_trailing_stop}, 开仓价: {entry_price}") + + #保存数据 + + def clear_position_info(self, instrument_id, direction): + """ + 清空指定合约和方向的持仓信息 + + Args: + instrument_id: 合约ID + direction: 方向 'long' 或 'short' 或 'all' + """ + # 确保合约ID在字典中存在 + if instrument_id not in self.stop_order_dict: + return + + if direction == 'long' or direction == 'all': + # 清空多头持仓信息 + self.stop_order_dict[instrument_id]['long'] = { + 'position': 0, + 'entry_price': 0, + 'stop_loss': 0, + 'take_profit': 0, + 'trailing_stop': 0 + } + # 兼容旧代码 + if direction == 'long': + self.long_trailing_stop_price = 0 + self.sl_long_price = 0 + + if direction == 'short' or direction == 'all': + # 清空空头持仓信息 + self.stop_order_dict[instrument_id]['short'] = { + 'position': 0, + 'entry_price': 0, + 'stop_loss': 0, + 'take_profit': 0, + 'trailing_stop': 0 + } + # 兼容旧代码 + if direction == 'short': + self.short_trailing_stop_price = 0 + self.sl_shor_price = 0 + + # 同步全局持仓状态 + if direction == 'all': + self.pos = 0 + self.long_trailing_stop_price = 0 + self.short_trailing_stop_price = 0 + self.sl_long_price = 0 + self.sl_shor_price = 0 + + # 保存到文件 + self.save_stop_orders_to_file(instrument_id) + self.save_to_csv(instrument_id) + + print(f"已清空{instrument_id}的{direction}持仓信息") + +# 修改call_deepseek_model函数,移除JSON格式输出的要求,改为从普通文本响应中提取交易信号。 +def call_deepseek_model(data_df, trader_instance, max_retries=2): + """ + 调用qwq-32b大模型分析订单流数据 + + Args: + data_df: 包含订单流数据的DataFrame + trader_instance: MyTrader实例,用于访问持仓信息 + max_retries: 最大重试次数 + + Returns: + dict: 包含交易信号的字典 + """ + # 直接从环境变量获取API密钥 + api_key = GLOBAL_LLM_CONFIG.get('api_key') + base_url = GLOBAL_LLM_CONFIG.get('base_url') + model_name = GLOBAL_LLM_CONFIG.get('model_name') + + # 检查API密钥是否为空 + if not api_key: + print("错误: API密钥未设置,请在main函数中配置GLOBAL_LLM_CONFIG['api_key']") + return {"action": "不操作", "reason": "API密钥未设置", "confidence": 0, "stop_loss": 0, "take_profit": 0} + + # 将DataFrame转换为可读性好的文本,传递trader_instance + data_text = trader_instance.format_data_for_llm(data_df) + + # 构建提示词 + prompt = f""" + 作为专注于趋势交易的期货交易员,基于以下市场数据做出交易决策: + + {data_text} + + 请重点考虑以下关键因素: + 1. 均线系统(5、10、20均线)的排列状态和金叉死叉信号 + 2. 价格是否处于明确的上升或下降通道中 + 3. 关键阻力位和支撑位的突破情况及其确认 + 4. 成交量是否配合价格趋势(上涨时放量,下跌时同样放量) + 5. 动量指标(MACD、KDJ等)的走势和信号 + 6. 订单流趋势与主力资金方向的一致性 + 7. 市场多空力量对比的持续性变化 + 8. 当前趋势的强度与持续时间评估 + + 【风险控制原则】: + - 严格控制每笔交易亏损不超过本金的1% + - 趋势交易的止损位应设置在次级回调位或关键技术位之下,通常为开仓价的0.3%-0.8% + - 使用移动止损机制跟踪趋势发展,锁定利润 + - 避免在盘整区间内频繁交易,等待明确的突破信号 + + 请根据市场状态和持仓情况,给出明确的交易指令: + 1. 交易方向: 不操作/开多/开空/平多/平空/平多开空/平空开多 + 2. 执行理由: 详细说明趋势特征、突破信号、动量变化和持续性评估 + 3. 置信度: 1-10的数字,反映趋势信号的清晰度,必须是整数 + 4. 止损价: 明确的止损价格(必须是数字),设置在关键支撑/阻力位附近 + 5. 止盈价: 明确的首个止盈目标(必须是数字),应至少是止损距离的1.5倍 + 6. 跟踪止损百分比: 0.001-0.01之间的数字,用于设置移动止损追踪趋势 + + 请按以下格式返回交易决策,格式必须严格匹配: + action: 不操作/开多/开空/平多/平空/平多开空/平空开多 + reason: 交易理由 + confidence: 置信度(1-10) + stop_loss: 止损价 + take_profit: 止盈价 + trailing_percent: 跟踪止损百分比(0.001-0.01) + """ + + system_prompt = {"role": "system", + "content": "你是一位专注于趋势交易的期货交易员,擅长识别和追踪强势趋势。你的交易风格注重动量和突破信号,善于在确认趋势后顺势而为,合理管理风险的同时最大化捕捉趋势利润。你特别关注均线系统、趋势线、成交量确认和动量指标,能精准判断趋势的强度和持续性。你擅长使用移动止损保护利润,在趋势延续时持有头寸,在趋势减弱时及时退出。请根据指定格式返回交易决策。"} + + # 添加重试机制 + retries = 0 + while retries <= max_retries: + try: + # 如果不是第一次尝试,输出重试信息 + if retries > 0: + print(f"正在进行第 {retries} 次重试...") + + # 调试信息 + print(f"使用API参数: base_url={base_url}, model={model_name}") + + # 添加明显的提示信息,表示正在调用大模型API + print("\n============================================") + print("【正在调用大模型API进行交易分析,请稍候...】") + print("============================================\n") + + # 记录开始时间 + api_start_time = time.time() + + # 使用OpenAI客户端格式调用API + client = OpenAI(api_key=api_key, base_url=base_url) + + # 发起流式请求 + response = client.chat.completions.create( + model=model_name, + messages=[ + system_prompt, + {"role": "user", "content": prompt} + ], + temperature=0.1, + stream=False, # 不启用流式模式 + max_tokens=8192, + timeout=60 + ) + + # 提取模型响应内容 + model_response = response.choices[0].message.content + + # 计算耗时 + api_elapsed = time.time() - api_start_time + print(f"\n\n模型响应总耗时: {api_elapsed:.2f}秒") + print("完整响应前100字符: " + model_response[:100] + "...") + + # 添加明显的提示信息,表示API调用已完成 + print("\n============================================") + print("【大模型API调用完成】") + print("============================================\n") + + # 从文本中解析出交易信号 + try: + trading_signal = parse_trading_signal(model_response) + return trading_signal + except Exception as parse_err: + print(f"解析模型响应出错: {parse_err}") + # 尝试从自由文本中提取关键信息 + return extract_trading_signal_from_text(model_response) + + except Exception as e: + retries += 1 + if retries <= max_retries: + print(f"调用大模型API出错: {e}") + print(f"将在3秒后重试...") + time.sleep(3) # 等待3秒后重试 + else: + print(f"已达到最大重试次数 ({max_retries}),调用大模型API失败") + print(f"错误详情: {e}") + print("\n请检查以下几点:") + print("1. API密钥格式是否正确,应以'sk-'开头") + print("2. 确认已安装最新版本的openai库: pip install --upgrade openai") + print("3. 确认您的API密钥对应的模型是否为deepseek-reasoner") + # 返回默认的不操作信号 + return {"action": "不操作", "reason": f"API调用失败: {str(e)[:100]}", "confidence": 0, "stop_loss": 0, "take_profit": 0} + + # 如果所有重试都失败了,返回默认值 + return {"action": "不操作", "reason": "API调用重试耗尽", "confidence": 0, "stop_loss": 0, "take_profit": 0} + +def parse_trading_signal(text): + """ + 从文本格式的模型响应中解析出交易信号 + + Args: + text: 模型响应文本 + + Returns: + dict: 包含交易信号的字典 + """ + lines = text.strip().split('\n') + trading_signal = {} + + for line in lines: + if ':' in line: + key, value = line.split(':', 1) + key = key.strip().lower() + value = value.strip() + + if key == 'action': + trading_signal['action'] = value + elif key == 'reason': + trading_signal['reason'] = value + elif key == 'confidence': + try: + trading_signal['confidence'] = int(value) + except ValueError: + # 尝试从文本中提取数字 + import re + match = re.search(r'\d+', value) + if match: + trading_signal['confidence'] = int(match.group()) + else: + trading_signal['confidence'] = 0 + elif key == 'stop_loss': + try: + trading_signal['stop_loss'] = float(value) + except ValueError: + # 尝试从文本中提取数字 + import re + match = re.search(r'\d+(\.\d+)?', value) + if match: + trading_signal['stop_loss'] = float(match.group()) + else: + trading_signal['stop_loss'] = 0 + elif key == 'take_profit': + try: + trading_signal['take_profit'] = float(value) + except ValueError: + # 尝试从文本中提取数字 + import re + match = re.search(r'\d+(\.\d+)?', value) + if match: + trading_signal['take_profit'] = float(match.group()) + else: + trading_signal['take_profit'] = 0 + elif key == 'trailing_percent' or key == 'trailing_stop_percent': + try: + value_float = float(value) + # 确保值在合理范围内 + if 0.0005 <= value_float <= 0.015: + trading_signal['trailing_percent'] = value_float + else: + # 如果值不在预期范围内,尝试判断是否使用了百分比格式 + if value_float >= 0.05 and value_float <= 1.5: + # 可能是百分比格式,转换为小数 + trading_signal['trailing_percent'] = value_float / 100 + else: + # 设置为默认值 + trading_signal['trailing_percent'] = 0.005 + except ValueError: + # 尝试从文本中提取数字 + import re + match = re.search(r'\d+(\.\d+)?', value) + if match: + try: + trailing_value = float(match.group()) + if trailing_value >= 0.5 and trailing_value <= 10: + trading_signal['trailing_percent'] = trailing_value / 100 + else: + trading_signal['trailing_percent'] = trailing_value + except: + trading_signal['trailing_percent'] = 0.02 + else: + trading_signal['trailing_percent'] = 0.02 + + # 检查是否有缺失的字段,如果有,设置默认值 + if 'action' not in trading_signal: + trading_signal['action'] = '不操作' + if 'reason' not in trading_signal: + trading_signal['reason'] = '未提供理由' + if 'confidence' not in trading_signal: + trading_signal['confidence'] = 0 + if 'stop_loss' not in trading_signal: + trading_signal['stop_loss'] = 0 + if 'take_profit' not in trading_signal: + trading_signal['take_profit'] = 0 + if 'trailing_percent' not in trading_signal: + trading_signal['trailing_percent'] = 0.005 # 修改默认值 + + return trading_signal + +def extract_trading_signal_from_text(text): + """ + 从自由格式文本中尝试提取交易信号 + + Args: + text: 模型响应文本 + + Returns: + dict: 包含交易信号的字典 + """ + # 默认交易信号 + trading_signal = { + "action": "不操作", + "reason": "无法解析模型响应", + "confidence": 0, + "stop_loss": 0, + "take_profit": 0, + "trailing_percent": 0.005 # 更新默认的跟踪止损百分比 + } + + # 尝试判断交易方向 + text_lower = text.lower() + if "平多开空" in text_lower: + trading_signal["action"] = "平多开空" + elif "平空开多" in text_lower: + trading_signal["action"] = "平空开多" + elif "开多" in text_lower: + trading_signal["action"] = "开多" + elif "开空" in text_lower: + trading_signal["action"] = "开空" + elif "平多" in text_lower: + trading_signal["action"] = "平多" + elif "平空" in text_lower: + trading_signal["action"] = "平空" + elif "不操作" in text_lower or "观望" in text_lower: + trading_signal["action"] = "不操作" + + # 尝试从文本中提取置信度 + import re + confidence_matches = re.findall(r'置信度[::]\s*(\d+)', text_lower) + if confidence_matches: + try: + trading_signal["confidence"] = int(confidence_matches[0]) + except ValueError: + pass + + # 尝试提取止损价 + stop_loss_matches = re.findall(r'止损价[::]\s*(\d+(\.\d+)?)', text_lower) + if stop_loss_matches: + try: + trading_signal["stop_loss"] = float(stop_loss_matches[0][0]) + except ValueError: + pass + + # 尝试提取止盈价 + take_profit_matches = re.findall(r'止盈价[::]\s*(\d+(\.\d+)?)', text_lower) + if take_profit_matches: + try: + trading_signal["take_profit"] = float(take_profit_matches[0][0]) + except ValueError: + pass + + # 尝试提取跟踪止损百分比 + trailing_matches = re.findall(r'跟踪止损百分比[::]\s*(\d+(\.\d+)?)', text_lower) + if not trailing_matches: + trailing_matches = re.findall(r'跟踪百分比[::]\s*(\d+(\.\d+)?)', text_lower) + + if trailing_matches: + try: + trailing_value = float(trailing_matches[0][0]) + # 判断是否为百分比格式 + if trailing_value >= 0.5 and trailing_value <= 10: + trading_signal["trailing_percent"] = trailing_value / 100 + else: + trading_signal["trailing_percent"] = trailing_value + except ValueError: + pass + + # 提取理由 + reason_matches = re.findall(r'理由[::]\s*(.*?)(?=\n|$)', text_lower) + if reason_matches: + trading_signal["reason"] = reason_matches[0] + + return trading_signal + +# 修改run_trader函数,改为接收统一的配置字典 +def run_trader(broker_id, td_server, investor_id, password, app_id, auth_code, md_queue=None, page_dir='', private_resume_type=2, public_resume_type=2, config=None): + # 设置全局变量 + global GLOBAL_LLM_CONFIG + + # 如果传入了配置字典,直接使用 + if config: + # 使用deepcopy避免潜在的引用问题 + GLOBAL_LLM_CONFIG = copy.deepcopy(config) + # else: + # # 确保有默认值 + # if 'bar_resample_rule' not in GLOBAL_LLM_CONFIG: + # GLOBAL_LLM_CONFIG['bar_resample_rule'] = '1T' + # if 'load_history' not in GLOBAL_LLM_CONFIG: + # GLOBAL_LLM_CONFIG['load_history'] = False + # if 'history_rows' not in GLOBAL_LLM_CONFIG: + # GLOBAL_LLM_CONFIG['history_rows'] = 1000 + # if 'trader_rows' not in GLOBAL_LLM_CONFIG: + # GLOBAL_LLM_CONFIG['trader_rows'] = 10 + + my_trader = MyTrader( + broker_id, + td_server, + investor_id, + password, + app_id, + auth_code, + md_queue, + page_dir, + private_resume_type, + public_resume_type + ) + + # 设置历史数据加载参数 + my_trader.load_history = GLOBAL_LLM_CONFIG['load_history'] + my_trader.history_rows = GLOBAL_LLM_CONFIG['history_rows'] + my_trader.trader_rows = GLOBAL_LLM_CONFIG['trader_rows'] + my_trader.Join() + +def ceshiapi(api_key): + # 测试API连接 + print(f"测试API连接,使用密钥: {api_key[:5]}...{api_key[-5:]}") + try: + client = OpenAI(api_key=api_key, base_url=GLOBAL_LLM_CONFIG['base_url'] ) + response = client.chat.completions.create( + model=GLOBAL_LLM_CONFIG['model_name'], + messages=[ + {"role": "system", "content": "你是一个助手"}, + {"role": "user", "content": "测试"} + ], + stream=False, # 新增此行 + max_tokens=10 + ) + print(f"API连接测试成功") + except Exception as e: + print(f"API连接测试失败: {e}") + import traceback + traceback.print_exc() + + + +# 修改主函数中的配置和调用方式 +if __name__ == '__main__': + + #公众号:松鼠Quant + #主页:www.quant789.com + #本策略仅作学习交流使用,实盘交易盈亏投资者个人负责!!! + #版权归松鼠Quant所有,禁止转发、转卖源码违者必究。 + + #注意:运行前请先安装好algoplus, + # pip install AlgoPlus + + + # 配置大模型参数 - 直接通过环境变量设置 + # 设置您的实际API密钥 + api_key = "" # 请确保使用有效的密钥 + # 同时设置到全局变量中 + GLOBAL_LLM_CONFIG['api_key'] = api_key + GLOBAL_LLM_CONFIG['base_url'] = "https://api.gptsapi.net/v1" + GLOBAL_LLM_CONFIG['model_name'] = "o3-mini-2025-01-31" + ceshiapi(api_key)# 测试API连接 + # 将所有配置参数整合到GLOBAL_LLM_CONFIG中 + # 历史数据加载配置 + GLOBAL_LLM_CONFIG['load_history'] = True # 是否加载历史数据 + GLOBAL_LLM_CONFIG['history_rows'] = 50 # 加载历史文件中数据量 + GLOBAL_LLM_CONFIG['trader_rows'] = 10 # 当tader_df里的数据大于10行时开始计算指标及触发AI模型 + # 设置K线时间粒度 + GLOBAL_LLM_CONFIG['bar_resample_rule'] = '3T' # 默认3分钟K线,可以修改为'5T'(5分钟),'15T'(15分钟)等,也可用'5S'(5秒),'30S'(30秒)或'1H'(1小时),'2H'(2小时),'4H'(4小时),'1D'(1天) + + + + #用simnow模拟,不要忘记屏蔽下方实盘的future_account字典 + future_account = get_simulate_account( + investor_id='', # simnow账户,注意是登录账户的ID,SIMNOW个人首页查看 + password='', # simnow密码 + server_name='电信1', # 电信1、电信2、移动、TEST、N视界 + subscribe_list=[b'au2506'], # 合约列表 + ) + + # #实盘用这个,不要忘记屏蔽上方simnow的future_account字典 + # future_account = FutureAccount( + # broker_id='', # 期货公司BrokerID + # server_dict={'TDServer': "ip:port", 'MDServer': 'ip:port'}, # TDServer为交易服务器,MDServer为行情服务器。服务器地址格式为"ip:port。" + # reserve_server_dict={}, # 备用服务器地址 + # investor_id='', # 账户 + # password='', # 密码 + # app_id='simnow_client_test', # 认证使用AppID + # auth_code='0000000000000000', # 认证使用授权码 + # subscribe_list=[b'rb2405'], # 订阅合约列表 + # md_flow_path='./log', # MdApi流文件存储地址,默认MD_LOCATION + # td_flow_path='./log', # TraderApi流文件存储地址,默认TD_LOCATION + # ) + + print('开始',len(future_account.subscribe_list)) + # 共享队列 + share_queue = Queue(maxsize=200) + + # 行情进程 + md_process = Process(target=run_tick_engine, args=(future_account, [share_queue])) + + # 使用深拷贝创建一个完全独立的配置副本 + import copy + config_copy = copy.deepcopy(GLOBAL_LLM_CONFIG) + + # 交易进程 - 增加历史数据加载参数和K线时间粒度参数 + trader_process = Process(target=run_trader, args=( + future_account.broker_id, + future_account.server_dict['TDServer'], + future_account.investor_id, + future_account.password, + future_account.app_id, + future_account.auth_code, + share_queue, # 队列 + future_account.td_flow_path, + 2, # private_resume_type + 2, # public_resume_type + config_copy, # 传递独立的配置副本,避免潜在的引用问题 + )) + + md_process.start() + trader_process.start() + + md_process.join() + trader_process.join() + + \ No newline at end of file diff --git a/1.交易策略/999.其他策略/4.松鼠SF20_基于LLM的订单流日内交易策略/使用文档/3.31版本/填写这里即可.png b/1.交易策略/999.其他策略/4.松鼠SF20_基于LLM的订单流日内交易策略/使用文档/3.31版本/填写这里即可.png new file mode 100644 index 0000000..041cc0e Binary files /dev/null and b/1.交易策略/999.其他策略/4.松鼠SF20_基于LLM的订单流日内交易策略/使用文档/3.31版本/填写这里即可.png differ diff --git a/1.交易策略/999.其他策略/4.松鼠SF20_基于LLM的订单流日内交易策略/使用文档/3.31版本/更新说明_3_31.txt b/1.交易策略/999.其他策略/4.松鼠SF20_基于LLM的订单流日内交易策略/使用文档/3.31版本/更新说明_3_31.txt new file mode 100644 index 0000000..3376dce --- /dev/null +++ b/1.交易策略/999.其他策略/4.松鼠SF20_基于LLM的订单流日内交易策略/使用文档/3.31版本/更新说明_3_31.txt @@ -0,0 +1,8 @@ +更新时间:2025年3月31日 +1.修复了GLOBAL_LLM_CONFIG在子进程里数值传递的问题。 + +2.新增大模型的日志保存:ai_analysis.log + +3.新增反手代码:平空开多,平多开空。 + +4.优化了日志输出,减少了冗余输出,监控时更加清晰。 \ No newline at end of file diff --git a/1.交易策略/999.其他策略/4.松鼠SF20_基于LLM的订单流日内交易策略/使用文档/4.02版本_new/.vscode/settings.json b/1.交易策略/999.其他策略/4.松鼠SF20_基于LLM的订单流日内交易策略/使用文档/4.02版本_new/.vscode/settings.json new file mode 100644 index 0000000..457f44d --- /dev/null +++ b/1.交易策略/999.其他策略/4.松鼠SF20_基于LLM的订单流日内交易策略/使用文档/4.02版本_new/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "python.analysis.typeCheckingMode": "basic" +} \ No newline at end of file diff --git a/1.交易策略/999.其他策略/4.松鼠SF20_基于LLM的订单流日内交易策略/使用文档/4.02版本_new/04.02更新日志.txt b/1.交易策略/999.其他策略/4.松鼠SF20_基于LLM的订单流日内交易策略/使用文档/4.02版本_new/04.02更新日志.txt new file mode 100644 index 0000000..314defc --- /dev/null +++ b/1.交易策略/999.其他策略/4.松鼠SF20_基于LLM的订单流日内交易策略/使用文档/4.02版本_new/04.02更新日志.txt @@ -0,0 +1,16 @@ +04.02更新: + +1.修复log已创建,无法新建连接不到行情的问题。原因:多进程问题。 + +2.修复固定止损止盈莫名改动的问题。原因: 成交回报那里又重新赋值了一次。 + +3.修复持仓信息保存报错进程问题。原因:多进程问题。 + +4.增加定时启动.py,可以24小时无人值守自动重启程序。 + +5.修复保存下午收盘与夜盘收盘最后一个bar数据未保存问题。 + +6.改善日志输出。 + +7.调整if __name__ == '__main__':代码的整洁 + diff --git a/1.交易策略/999.其他策略/4.松鼠SF20_基于LLM的订单流日内交易策略/使用文档/4.02版本_new/traderdata/au2506_ofdata.json b/1.交易策略/999.其他策略/4.松鼠SF20_基于LLM的订单流日内交易策略/使用文档/4.02版本_new/traderdata/au2506_ofdata.json new file mode 100644 index 0000000..85c4af0 --- /dev/null +++ b/1.交易策略/999.其他策略/4.松鼠SF20_基于LLM的订单流日内交易策略/使用文档/4.02版本_new/traderdata/au2506_ofdata.json @@ -0,0 +1,387 @@ +{"price":["728.08","728.1","728.12","728.14","728.16","728.18","728.2","728.24","728.26","728.28","728.3","728.32","728.34","728.36","728.38","728.4","728.42","728.44","728.46","728.48","728.5","728.52","728.54","728.56","728.58","728.6","728.62","728.64","728.66","728.68","728.7","728.72","728.74","728.76","728.78","728.8","728.82","728.84","728.86","728.88","728.9","728.92"],"Ask":[0,43,0,14,12,79,8,0,42,54,10,6,40,9,11,0,35,97,139,71,77,28,19,90,6,18,11,24,23,149,63,57,153,61,53,143,30,0,19,0,28,53],"Bid":[17,50,3,46,18,24,16,15,80,26,49,18,13,3,11,19,79,104,64,6,49,21,35,24,10,21,19,0,42,63,75,64,80,74,69,0,19,98,84,29,26,45],"symbol":"au2506","datetime":"2025-03-31 13:33:00","delta":167.0,"close":728.08,"open":728.5,"high":728.92,"low":728.08,"volume":3900,"dj":-1,"dayma":728.08,"delta累计":167.0} +{"price":["728.1","728.12","728.14","728.16","728.18","728.2","728.22","728.24","728.26","728.28","728.3","728.32","728.34","728.36","728.38","728.4","728.42","728.44","728.46"],"Ask":[0,27,27,79,19,59,80,14,1,41,62,110,23,87,34,58,101,38,10],"Bid":[36,9,92,78,17,50,28,3,6,33,61,61,63,91,2,16,39,20,0],"symbol":"au2506","datetime":"2025-03-31 13:36:00","delta":165.0,"close":728.4,"open":728.1,"high":728.46,"low":728.1,"volume":1721,"dj":0,"dayma":728.24,"delta累计":332.0} +{"price":["728.32","728.34","728.36","728.38","728.4","728.42","728.44","728.46","728.48","728.5","728.52","728.54","728.56","728.58","728.6","728.62","728.64","728.66","728.68","728.7"],"Ask":[0,4,0,0,45,7,99,101,58,86,81,74,72,41,27,32,27,10,20,12],"Bid":[24,20,32,32,38,48,45,53,57,108,48,82,20,25,8,10,25,25,47,0],"symbol":"au2506","datetime":"2025-03-31 13:39:00","delta":49.0,"close":728.64,"open":728.4,"high":728.7,"low":728.32,"volume":1695,"dj":-1,"dayma":728.3733333333,"delta累计":381.0} +{"price":["728.62","728.64","728.66","728.68","728.7","728.72","728.74","728.76","728.78","728.8","728.82","728.84","728.86","728.88","728.9","728.92","728.94","728.96","728.98","729.0","729.02","729.04"],"Ask":[0,5,8,50,96,31,72,66,84,167,117,96,83,74,25,46,15,56,49,66,39,42],"Bid":[2,0,37,30,0,71,25,56,184,195,37,76,59,16,20,80,46,19,38,0,75,0],"symbol":"au2506","datetime":"2025-03-31 13:42:00","delta":221.0,"close":728.96,"open":728.64,"high":729.04,"low":728.62,"volume":2463,"dj":0,"dayma":728.52,"delta累计":602.0} +{"price":["728.86","728.88","728.9","728.92","728.94","728.96","728.98","729.0","729.02","729.04","729.06","729.08","729.1","729.12","729.14","729.16"],"Ask":[0,44,83,48,116,158,69,180,41,6,2,31,43,78,15,21],"Bid":[37,99,87,80,68,78,80,113,126,20,4,73,23,56,14,0],"symbol":"au2506","datetime":"2025-03-31 13:45:00","delta":-23.0,"close":728.98,"open":728.94,"high":729.16,"low":728.86,"volume":2031,"dj":0,"dayma":728.612,"delta累计":579.0} +{"price":["728.8","728.82","728.84","728.86","728.88","728.9","728.92","728.94","728.96","728.98","729.0","729.02","729.04","729.06","729.08","729.1"],"Ask":[0,68,76,38,95,92,29,50,117,16,7,51,25,25,23,13],"Bid":[17,69,53,89,78,77,88,41,40,0,19,21,22,25,0,0],"symbol":"au2506","datetime":"2025-03-31 13:48:00","delta":86.0,"close":728.9,"open":728.94,"high":729.1,"low":728.8,"volume":1470,"dj":0,"dayma":728.66,"delta累计":665.0} +{"price":["728.62","728.64","728.66","728.68","728.7","728.72","728.74","728.76","728.78","728.8","728.82","728.84","728.86","728.88","728.9","728.92","728.94","728.96","728.98","729.0","729.04"],"Ask":[0,11,105,31,73,68,66,16,91,16,41,17,5,45,52,37,13,13,14,37,11],"Bid":[67,43,86,50,52,92,52,12,123,66,62,16,63,39,75,65,39,0,7,45,0],"symbol":"au2506","datetime":"2025-03-31 13:51:00","delta":-292.0,"close":728.78,"open":728.9,"high":729.04,"low":728.62,"volume":1905,"dj":0,"dayma":728.6771428571,"delta累计":373.0} +{"price":["728.7","728.72","728.74","728.76","728.78","728.8","728.82","728.84","728.86","728.88","728.9","728.92","728.94","728.96","728.98","729.0","729.02","729.04","729.06","729.08","729.1","729.12","729.14","729.16","729.2","729.22","729.24","729.26","729.28","729.3","729.34","729.36","729.38","729.4","729.42","729.44","729.46","729.48","729.5","729.52","729.54","729.56","729.6","729.62","729.68","729.7","729.72","729.74","729.78","729.8","729.82","729.84"],"Ask":[0,0,3,10,73,15,84,24,2,11,26,13,28,29,11,61,30,13,38,22,21,7,14,7,63,7,52,11,29,14,36,20,15,0,9,28,0,16,131,132,34,87,0,39,23,27,33,0,42,0,0,20],"Bid":[3,1,66,17,63,25,39,22,18,18,9,3,20,27,0,0,2,48,6,0,5,10,0,0,0,18,27,40,0,0,16,25,18,9,19,54,17,59,221,87,0,39,16,0,0,0,35,42,72,13,18,0],"symbol":"au2506","datetime":"2025-03-31 13:54:00","delta":163.0,"close":729.82,"open":728.78,"high":729.84,"low":728.7,"volume":2872,"dj":3,"dayma":728.82,"delta累计":536.0} +{"price":["729.58","729.6","729.62","729.64","729.66","729.68","729.7","729.72","729.74","729.76","729.78","729.8","729.82","729.84","729.86","729.88","729.9","729.92","729.94","729.96","729.98","730.0","730.02","730.04","730.06","730.08","730.1","730.12","730.14","730.16","730.18"],"Ask":[0,0,60,96,57,79,140,117,33,38,24,16,56,30,43,89,32,27,52,58,75,234,122,44,71,112,18,83,17,166,20],"Bid":[15,50,68,70,63,98,24,7,56,88,39,63,29,85,99,78,5,35,88,61,97,124,181,31,18,66,26,11,54,29,0],"symbol":"au2506","datetime":"2025-03-31 13:57:00","delta":251.0,"close":729.58,"open":729.82,"high":730.18,"low":729.58,"volume":4085,"dj":0,"dayma":728.9044444444,"delta累计":787.0} +{"price":["729.56","729.58","729.6","729.64","729.66","729.68","729.7","729.72","729.76","729.78","729.8","729.82","729.84","729.86","729.88","729.9","729.92","729.94","729.96","729.98","730.0"],"Ask":[0,40,8,10,7,7,4,9,0,5,15,49,116,74,192,78,106,53,19,23,20],"Bid":[10,6,9,0,5,0,0,6,10,74,61,100,144,91,163,126,43,6,10,16,0],"symbol":"au2506","datetime":"2025-03-31 14:00:00","delta":-45.0,"close":729.82,"open":729.58,"high":730.0,"low":729.56,"volume":1866,"dj":0,"dayma":728.996,"delta累计":742.0} +{"price":["729.44","729.46","729.48","729.5","729.52","729.54","729.56","729.58","729.6","729.62","729.64","729.66","729.68","729.7","729.72","729.74","729.76","729.78","729.8","729.82","729.84","729.86","729.88","729.9","729.92","729.94","729.96","729.98","730.0","730.02","730.04","730.06","730.08","730.1","730.12","730.14","730.16","730.18","730.2","730.24","730.26","730.28","730.3","730.32","730.34","730.36"],"Ask":[0,0,0,42,26,47,37,2,17,56,100,68,4,40,55,40,14,22,9,65,92,116,69,17,0,26,64,34,66,21,15,46,3,19,8,0,11,30,48,0,18,27,16,28,29,75],"Bid":[9,76,33,31,8,18,125,23,66,9,38,6,51,15,45,6,12,57,59,85,137,51,2,56,7,22,7,30,25,29,13,38,21,6,52,28,0,15,56,12,49,0,0,33,64,0],"symbol":"au2506","datetime":"2025-03-31 14:03:00","delta":-3.0,"close":730.28,"open":729.82,"high":730.36,"low":729.44,"volume":3338,"dj":0,"dayma":729.1127272727,"delta累计":739.0} +{"price":["729.98","730.0","730.02","730.06","730.08","730.1","730.12","730.14","730.16","730.18","730.2","730.22","730.24","730.26","730.28","730.3","730.32","730.34","730.36","730.38","730.4","730.42","730.44","730.46","730.48","730.5","730.52"],"Ask":[0,22,6,20,57,27,39,4,79,62,84,71,82,77,73,74,0,16,25,14,42,81,93,70,59,177,24],"Bid":[5,47,16,43,10,55,24,33,87,66,100,40,43,125,19,26,2,22,17,24,77,49,56,32,43,16,0],"symbol":"au2506","datetime":"2025-03-31 14:06:00","delta":301.0,"close":730.46,"open":730.26,"high":730.54,"low":729.98,"volume":2721,"dj":0,"dayma":729.225,"delta累计":1040.0} +{"price":["730.28","730.32","730.34","730.36","730.38","730.4","730.42","730.44","730.46","730.48","730.5","730.52","730.54","730.56","730.58","730.6","730.62"],"Ask":[0,0,26,22,51,93,80,141,127,35,113,147,42,51,134,88,17],"Bid":[31,18,25,81,63,102,106,24,51,40,44,56,38,91,35,122,11],"symbol":"au2506","datetime":"2025-03-31 14:09:00","delta":229.0,"close":730.6,"open":730.46,"high":730.62,"low":730.28,"volume":2369,"dj":0,"dayma":729.3307692308,"delta累计":1269.0} +{"price":["730.62","730.64","730.66","730.7","730.72","730.76","730.78","730.8","730.82","730.84","730.86","730.88","730.9","730.92","730.94","730.96","730.98","731.0","731.02","731.04","731.06","731.08","731.1","731.12","731.16","731.18"],"Ask":[7,6,30,59,28,0,24,0,24,0,42,153,134,87,61,40,212,35,181,184,114,78,110,76,0,49],"Bid":[0,34,0,0,0,42,22,29,43,75,31,86,75,73,123,90,211,215,128,89,164,70,0,59,13,0],"symbol":"au2506","datetime":"2025-03-31 14:12:00","delta":62.0,"close":731.02,"open":730.62,"high":731.18,"low":730.62,"volume":3869,"dj":0,"dayma":729.4514285714,"delta累计":1331.0} +{"price":["731.02","731.04","731.06","731.08","731.12","731.14","731.16","731.18","731.2","731.22","731.24","731.26","731.28","731.3","731.32","731.34","731.36","731.38","731.4","731.42","731.44","731.46","731.48","731.5","731.52","731.54","731.56","731.58","731.6","731.62","731.64","731.66","731.68","731.7","731.72","731.74","731.76","731.78","731.8","731.82","731.84","731.86","731.88","731.9","731.92","731.94","731.96","731.98","732.0","732.04","732.06","732.08","732.1"],"Ask":[0,38,43,12,6,31,214,35,85,44,70,89,0,74,150,54,9,123,91,43,68,99,138,20,67,0,71,106,17,22,12,43,0,0,0,0,27,83,73,59,126,60,0,40,31,11,32,45,131,0,0,129,96],"Bid":[19,32,6,13,28,25,71,26,45,27,118,38,17,0,68,29,10,66,44,117,86,11,64,85,40,50,60,84,3,0,0,22,9,20,44,34,20,61,94,311,63,18,20,0,21,0,0,34,11,20,24,0,0],"symbol":"au2506","datetime":"2025-03-31 14:15:00","delta":709.0,"close":731.46,"open":731.06,"high":732.1,"low":731.02,"volume":5522,"dj":0,"dayma":729.5853333333,"delta累计":2040.0} +{"price":["731.0","731.02","731.04","731.06","731.08","731.1","731.12","731.14","731.16","731.18","731.2","731.22","731.24","731.26","731.28","731.3","731.32","731.34","731.36","731.38","731.4","731.42","731.44","731.46","731.48","731.5"],"Ask":[24,183,79,126,103,53,110,80,54,104,80,46,73,8,49,62,18,22,6,11,0,7,17,46,61,16],"Bid":[97,55,69,91,92,58,77,59,27,90,48,17,84,44,25,50,18,11,11,0,27,35,34,67,11,0],"symbol":"au2506","datetime":"2025-03-31 14:18:00","delta":241.0,"close":731.06,"open":731.46,"high":731.5,"low":731.0,"volume":2933,"dj":0,"dayma":729.6775,"delta累计":2281.0} +{"price":["730.66","730.68","730.7","730.72","730.74","730.76","730.78","730.8","730.82","730.84","730.86","730.88","730.9","730.92","730.94","730.96","730.98","731.0","731.02","731.04","731.06","731.08","731.1","731.12"],"Ask":[20,21,82,94,175,48,90,103,185,97,71,25,28,31,28,14,93,76,88,29,14,55,29,3],"Bid":[41,4,47,149,44,90,72,19,189,52,52,56,113,81,3,46,104,58,56,47,0,30,3,0],"symbol":"au2506","datetime":"2025-03-31 14:21:00","delta":143.0,"close":730.76,"open":731.08,"high":731.12,"low":730.66,"volume":3134,"dj":0,"dayma":729.7411764706,"delta累计":2424.0} +{"price":["730.72","730.74","730.76","730.78","730.8","730.82","730.84","730.86","730.88","730.9","730.92","730.94","730.96","730.98","731.0","731.02","731.04","731.06","731.08","731.1","731.12","731.14","731.16"],"Ask":[0,10,45,44,61,63,17,84,36,45,108,34,82,40,55,60,10,14,75,35,76,25,10],"Bid":[78,13,33,12,34,59,31,35,80,48,27,16,37,61,8,7,50,45,70,36,39,25,14],"symbol":"au2506","datetime":"2025-03-31 14:24:00","delta":171.0,"close":730.94,"open":730.74,"high":731.16,"low":730.72,"volume":2229,"dj":0,"dayma":729.8077777778,"delta累计":2595.0} +{"price":["730.12","730.14","730.18","730.2","730.22","730.24","730.26","730.28","730.3","730.32","730.34","730.36","730.38","730.4","730.42","730.44","730.46","730.48","730.5","730.52","730.54","730.56","730.58","730.6","730.62","730.66","730.68","730.7","730.72","730.74","730.76","730.8","730.82","730.84","730.86","730.9","730.92","730.94","730.96","730.98"],"Ask":[0,0,66,0,57,25,46,39,34,20,83,23,12,53,62,74,85,26,76,76,52,106,14,29,0,21,26,28,0,27,12,17,0,0,15,4,0,14,22,2],"Bid":[45,49,9,12,15,90,9,85,50,16,60,35,36,73,144,138,127,40,126,121,29,29,12,33,9,0,6,35,6,4,8,37,4,2,13,0,20,9,5,0],"symbol":"au2506","datetime":"2025-03-31 14:27:00","delta":-295.0,"close":730.18,"open":730.92,"high":730.98,"low":730.12,"volume":3009,"dj":0,"dayma":729.8273684211,"delta累计":2300.0} +{"price":["730.16","730.18","730.2","730.22","730.24","730.26","730.28","730.3","730.32","730.34","730.36","730.38","730.4","730.42","730.44","730.46","730.48","730.5","730.52","730.54","730.56","730.58","730.6","730.62","730.64","730.66"],"Ask":[16,40,5,2,45,27,2,114,112,27,50,73,115,46,16,19,34,78,29,22,37,27,119,44,74,14],"Bid":[13,19,5,0,7,26,43,91,63,20,53,47,100,22,8,41,44,29,36,15,44,97,34,0,0,0],"symbol":"au2506","datetime":"2025-03-31 14:30:00","delta":330.0,"close":730.54,"open":730.18,"high":730.66,"low":730.16,"volume":2345,"dj":0,"dayma":729.863,"delta累计":2630.0} +{"price":["730.2","730.22","730.24","730.26","730.28","730.3","730.32","730.34","730.36","730.38","730.4","730.42","730.44","730.46","730.48","730.5","730.52","730.54","730.56","730.58","730.6","730.62","730.64","730.66","730.68","730.7","730.72","730.78","730.8","730.82","730.84","730.86","730.88","730.9","730.92","730.94"],"Ask":[39,15,0,123,10,56,88,14,10,47,76,104,24,97,12,41,23,17,17,38,53,50,57,20,72,39,20,23,19,10,0,100,41,54,27,25],"Bid":[122,5,51,11,13,0,17,10,19,148,79,29,16,23,20,21,38,14,46,28,106,32,49,26,10,39,0,51,33,35,59,58,32,15,13,0],"symbol":"au2506","datetime":"2025-03-31 14:33:00","delta":193.0,"close":730.2,"open":730.56,"high":730.94,"low":730.2,"volume":3049,"dj":0,"dayma":729.879047619,"delta累计":2823.0} +{"price":["729.62","729.64","729.66","729.68","729.7","729.72","729.74","729.76","729.78","729.8","729.82","729.84","729.86","729.88","729.9","729.92","729.94","729.96","729.98","730.0","730.02","730.04","730.06","730.08","730.1","730.12","730.14","730.16","730.18","730.2","730.22","730.24"],"Ask":[0,11,0,37,9,0,47,18,27,32,4,151,68,181,81,52,66,197,117,120,29,164,99,14,62,4,39,6,0,36,32,9],"Bid":[15,0,58,64,0,31,0,53,111,11,0,53,77,54,81,102,68,144,54,166,58,50,12,65,58,10,14,53,49,24,12,3],"symbol":"au2506","datetime":"2025-03-31 14:36:00","delta":162.0,"close":730.06,"open":730.22,"high":730.3,"low":729.62,"volume":3693,"dj":0,"dayma":729.8872727273,"delta累计":2985.0} +{"price":["729.66","729.68","729.7","729.72","729.74","729.76","729.78","729.8","729.82","729.84","729.86","729.88","729.9","729.92","729.94","729.96","729.98","730.0","730.02","730.04","730.06","730.08","730.1","730.12","730.14","730.16","730.18","730.2","730.22","730.24","730.26","730.28"],"Ask":[11,0,45,13,20,88,6,78,45,0,21,85,35,32,24,32,4,11,18,0,2,36,33,10,3,31,36,54,39,0,22,38],"Bid":[20,13,52,154,19,52,4,25,8,17,85,108,23,28,52,24,15,32,11,24,10,53,21,17,19,44,20,17,47,34,41,0],"symbol":"au2506","datetime":"2025-03-31 14:39:00","delta":-217.0,"close":729.88,"open":730.1,"high":730.28,"low":729.66,"volume":2152,"dj":0,"dayma":729.8869565217,"delta累计":2768.0} +{"price":["729.72","729.74","729.76","729.78","729.8","729.82","729.84","729.86","729.88","729.9","729.92","729.94","729.96","729.98","730.0","730.02","730.04","730.06","730.08"],"Ask":[0,54,5,32,2,15,51,30,66,45,66,94,76,38,79,34,9,5,43],"Bid":[12,6,12,10,19,23,20,26,57,90,154,57,54,87,19,42,29,32,0],"symbol":"au2506","datetime":"2025-03-31 14:42:00","delta":-5.0,"close":729.86,"open":729.88,"high":730.08,"low":729.72,"volume":1623,"dj":0,"dayma":729.8858333333,"delta累计":2763.0} +{"price":["729.16","729.18","729.2","729.22","729.26","729.28","729.3","729.32","729.34","729.36","729.38","729.4","729.42","729.44","729.46","729.48","729.5","729.52","729.54","729.56","729.58","729.6","729.62","729.64","729.66","729.68","729.7","729.72","729.74","729.76","729.78","729.8","729.82","729.84","729.86","729.88","729.9","729.92","729.94","729.96"],"Ask":[39,73,0,141,23,11,26,0,9,17,14,0,0,30,73,48,19,91,65,76,31,71,83,19,31,0,0,9,0,0,2,42,106,18,52,40,7,35,25,41],"Bid":[78,37,10,0,0,0,51,26,0,0,12,42,19,48,0,16,71,95,18,109,88,66,5,0,13,14,15,11,14,26,36,219,95,24,35,58,42,56,2,7],"symbol":"au2506","datetime":"2025-03-31 14:45:00","delta":-91.0,"close":729.18,"open":729.84,"high":729.96,"low":729.16,"volume":3035,"dj":1,"dayma":729.8576,"delta累计":2672.0} +{"price":["728.8","728.82","728.84","728.86","728.88","728.9","728.92","728.94","728.96","728.98","729.0","729.02","729.04","729.06","729.08","729.1","729.12","729.14","729.16","729.18","729.2","729.22","729.24","729.26","729.28","729.3","729.32","729.34","729.36"],"Ask":[0,0,30,93,57,67,41,79,20,83,169,61,104,59,53,92,61,78,82,0,86,77,162,84,89,14,6,26,36],"Bid":[50,17,8,45,130,36,58,132,55,13,117,66,50,78,27,117,49,63,46,18,116,111,70,21,49,9,28,0,0],"symbol":"au2506","datetime":"2025-03-31 14:48:00","delta":230.0,"close":729.06,"open":729.24,"high":729.36,"low":728.8,"volume":3757,"dj":0,"dayma":729.8269230769,"delta累计":2902.0} +{"price":["728.5","728.54","728.56","728.58","728.6","728.62","728.64","728.66","728.68","728.7","728.72","728.74","728.76","728.78","728.8","728.82","728.84","728.86","728.88","728.9","728.92","728.94","728.96","728.98","729.0","729.02","729.04","729.06","729.08","729.1","729.12","729.14","729.16","729.18","729.2","729.22","729.24"],"Ask":[0,93,5,88,14,62,77,225,47,94,46,32,10,18,23,59,5,57,12,78,32,85,79,18,35,26,7,43,38,21,14,3,71,10,74,30,46],"Bid":[54,89,24,21,34,106,142,27,15,62,5,0,25,64,44,93,74,38,34,76,20,71,0,81,29,14,33,81,1,0,4,4,37,103,19,1,0],"symbol":"au2506","datetime":"2025-03-31 14:51:00","delta":152.0,"close":729.24,"open":729.06,"high":729.24,"low":728.5,"volume":3497,"dj":0,"dayma":729.8051851852,"delta累计":3054.0} +{"price":["728.98","729.0","729.02","729.04","729.06","729.08","729.1","729.12","729.14","729.16","729.18","729.2","729.22","729.24","729.26","729.28","729.3","729.32","729.34","729.36","729.38","729.4","729.42","729.44","729.46","729.48","729.5","729.52","729.54","729.56","729.58"],"Ask":[0,0,35,82,52,42,84,41,6,43,36,15,31,55,4,66,10,60,32,71,32,91,30,32,28,28,24,11,3,33,47],"Bid":[3,51,94,32,81,45,13,27,18,23,26,54,44,28,12,14,69,71,66,28,8,65,9,0,28,28,10,12,7,14,0],"symbol":"au2506","datetime":"2025-03-31 14:54:00","delta":144.0,"close":729.28,"open":729.22,"high":729.58,"low":728.98,"volume":2229,"dj":0,"dayma":729.7864285714,"delta累计":3198.0} +{"price":["728.96","728.98","729.0","729.02","729.04","729.06","729.08","729.1","729.12","729.14","729.16","729.18","729.2","729.22","729.24","729.26","729.28","729.3","729.32","729.34","729.36","729.38","729.4","729.42","729.44","729.46","729.48","729.5","729.52","729.54","729.56","729.58","729.6"],"Ask":[0,0,46,42,22,30,4,19,24,20,4,13,54,27,7,73,68,6,26,13,25,47,66,25,44,25,16,41,27,51,42,58,17],"Bid":[13,4,50,42,4,24,9,14,32,11,12,15,62,19,19,12,37,30,12,4,34,45,25,0,5,14,4,19,12,30,17,27,0],"symbol":"au2506","datetime":"2025-03-31 14:57:00","delta":325.0,"close":729.44,"open":729.24,"high":729.6,"low":728.96,"volume":1851,"dj":0,"dayma":729.7744827586,"delta累计":3523.0} +{"price":[],"Ask":[],"Bid":[],"symbol":"au2506","datetime":"2025-03-31 21:00:00","delta":0.0,"close":731.66,"open":731.66,"high":731.66,"low":731.66,"volume":67,"dj":0,"dayma":729.8373333333,"delta累计":3523.0} +{"price":["731.14","731.16","731.18","731.2","731.22","731.24","731.26","731.28","731.3","731.32","731.34","731.36","731.38","731.4","731.42","731.44","731.46","731.48","731.5","731.52","731.54","731.56","731.58","731.6","731.62","731.64","731.66","731.68","731.7","731.72","731.74","731.76"],"Ask":[107,0,18,185,136,67,182,66,102,109,37,126,70,242,75,131,104,94,86,61,177,76,95,20,89,51,64,133,80,35,41,52],"Bid":[143,127,0,37,42,240,66,163,260,153,325,71,132,206,101,70,68,28,246,43,290,24,107,60,73,38,99,109,21,86,50,0],"symbol":"au2506","datetime":"2025-03-31 21:03:00","delta":-567.0,"close":731.2,"open":731.54,"high":731.76,"low":731.14,"volume":7036,"dj":0,"dayma":729.8812903226,"delta累计":2956.0} +{"price":["729.6","729.62","729.64","729.66","729.68","729.7","729.72","729.74","729.76","729.78","729.8","729.82","729.84","729.86","729.88","729.9","729.92","729.94","729.96","729.98","730.0","730.02","730.04","730.06","730.08","730.14","730.16","730.18","730.2","730.22","730.24","730.4","730.48","730.5","730.52","730.54","730.6","730.62","730.64","730.66","730.68","730.7","730.72","730.74","730.76","730.78","730.8","730.82","730.84","730.86","730.88","730.9","730.92","730.94","730.96","730.98","731.0","731.02","731.12","731.14","731.16"],"Ask":[0,39,0,10,23,33,68,0,0,70,31,69,120,45,32,0,61,0,57,104,136,91,0,3,0,0,13,116,136,29,19,0,0,24,0,21,0,11,33,24,11,37,171,32,54,43,87,40,0,63,66,75,31,98,75,147,108,0,0,0,28],"Bid":[15,9,30,0,0,65,57,51,10,102,63,19,104,87,11,6,155,63,15,63,86,44,37,0,32,57,28,140,127,36,0,67,6,22,18,39,13,6,45,12,53,114,132,117,63,68,74,0,74,47,105,198,41,82,144,106,140,32,13,14,27],"symbol":"au2506","datetime":"2025-03-31 21:06:00","delta":-800.0,"close":729.7,"open":731.18,"high":731.18,"low":729.6,"volume":6650,"dj":-1,"dayma":729.875625,"delta累计":2156.0} +{"price":["729.3","729.32","729.34","729.4","729.42","729.44","729.46","729.48","729.5","729.52","729.54","729.58","729.6","729.62","729.64","729.66","729.68","729.7","729.72","729.74","729.76","729.78","729.8","729.82","729.84","729.86","729.88","729.9","729.92","729.94","729.96","729.98","730.0","730.02","730.04","730.06","730.08","730.1","730.12","730.14","730.16","730.18","730.2","730.22","730.24","730.26","730.28","730.3","730.4"],"Ask":[0,40,42,0,34,47,30,37,0,21,55,26,76,109,82,6,37,29,65,167,139,222,47,162,126,44,32,53,77,35,93,36,40,59,41,10,62,67,102,126,42,51,100,151,62,53,29,52,31],"Bid":[36,0,0,63,0,46,21,0,51,0,86,35,72,43,12,44,22,45,70,96,89,128,117,177,9,11,134,24,97,19,65,3,14,37,28,69,33,85,50,67,0,102,55,66,62,38,14,12,0],"symbol":"au2506","datetime":"2025-03-31 21:09:00","delta":700.0,"close":730.22,"open":729.7,"high":730.4,"low":729.3,"volume":6344,"dj":0,"dayma":729.8860606061,"delta累计":2856.0} +{"price":["730.06","730.08","730.1","730.12","730.14","730.16","730.18","730.2","730.22","730.24","730.26","730.28","730.3","730.32","730.34","730.36","730.38","730.4","730.42","730.44","730.46","730.48","730.5","730.52","730.54","730.56","730.58","730.6","730.62","730.64","730.66","730.68","730.7","730.72","730.74","730.76","730.78","730.8","730.82","730.84","730.86","730.88"],"Ask":[14,0,13,16,36,0,37,33,11,45,61,75,114,103,65,85,69,155,16,22,70,7,24,12,7,0,47,107,87,45,14,34,35,81,42,36,44,86,41,16,7,36],"Bid":[31,19,61,28,1,16,63,82,31,55,70,162,109,37,20,23,32,50,22,14,25,0,12,42,43,9,10,71,30,56,11,29,79,111,48,33,9,42,63,54,25,45],"symbol":"au2506","datetime":"2025-03-31 21:12:00","delta":75.0,"close":730.64,"open":730.24,"high":730.88,"low":730.06,"volume":3943,"dj":0,"dayma":729.9082352941,"delta累计":2931.0} +{"price":["730.08","730.12","730.14","730.16","730.18","730.2","730.22","730.24","730.26","730.28","730.3","730.32","730.34","730.36","730.38","730.4","730.42","730.44","730.46","730.48","730.5","730.52","730.54","730.56","730.58","730.6","730.62","730.64"],"Ask":[0,44,31,113,52,29,29,60,25,128,104,110,18,55,119,21,31,59,13,37,48,30,51,26,16,23,21,3],"Bid":[11,24,183,86,60,3,32,29,14,194,158,133,26,54,55,32,162,30,29,44,87,94,43,14,27,63,23,8],"symbol":"au2506","datetime":"2025-03-31 21:15:00","delta":-422.0,"close":730.44,"open":730.64,"high":730.64,"low":730.08,"volume":3254,"dj":0,"dayma":729.9234285714,"delta累计":2509.0} +{"price":["730.32","730.34","730.36","730.38","730.4","730.42","730.44","730.46","730.48","730.5","730.52","730.54","730.56","730.58","730.6","730.62","730.64","730.66","730.68","730.7","730.72","730.74"],"Ask":[24,23,9,36,144,141,49,55,89,124,67,47,5,44,9,65,31,49,38,45,13,2],"Bid":[20,60,17,96,129,132,63,19,71,113,50,0,19,52,37,48,0,58,78,17,0,0],"symbol":"au2506","datetime":"2025-03-31 21:18:00","delta":30.0,"close":730.6,"open":730.44,"high":730.74,"low":730.32,"volume":2422,"dj":0,"dayma":729.9422222222,"delta累计":2539.0} +{"price":["730.54","730.56","730.58","730.6","730.62","730.64","730.66","730.7","730.72","730.74","730.76","730.78","730.8","730.82","730.84","730.86","730.88","730.9","730.92","730.94","730.96","730.98","731.0","731.02","731.04","731.06","731.08","731.1","731.12","731.14","731.16","731.18"],"Ask":[0,6,25,28,17,10,9,5,24,5,18,12,22,0,61,73,206,172,98,30,119,191,40,91,36,43,67,57,60,6,10,23],"Bid":[39,21,13,12,7,1,0,0,0,0,10,30,52,12,47,105,65,104,64,60,80,145,3,23,110,9,24,117,12,55,17,8],"symbol":"au2506","datetime":"2025-03-31 21:21:00","delta":319.0,"close":731.1,"open":730.56,"high":731.18,"low":730.54,"volume":3122,"dj":3,"dayma":729.9735135135,"delta累计":2858.0} +{"price":["730.36","730.4","730.42","730.44","730.46","730.48","730.5","730.52","730.54","730.56","730.58","730.6","730.62","730.64","730.66","730.68","730.7","730.72","730.74","730.76","730.78","730.8","730.82","730.84","730.86","730.88","730.9","730.92","731.0","731.02","731.04","731.06","731.08","731.1","731.12","731.14","731.16","731.18"],"Ask":[0,19,23,102,45,0,32,42,27,67,66,103,134,30,83,45,23,52,38,47,41,110,12,24,68,17,28,2,0,0,0,48,12,55,21,10,87,69],"Bid":[17,22,0,66,59,20,84,21,53,22,91,76,34,23,71,6,27,38,30,125,167,64,15,35,28,20,14,3,60,11,7,10,19,0,38,38,6,0],"symbol":"au2506","datetime":"2025-03-31 21:24:00","delta":162.0,"close":730.64,"open":731.12,"high":731.18,"low":730.36,"volume":3348,"dj":-2,"dayma":729.9910526316,"delta累计":3020.0} +{"price":["729.96","729.98","730.0","730.02","730.04","730.06","730.1","730.12","730.16","730.22","730.26","730.3","730.32","730.34","730.36","730.38","730.4","730.42","730.44","730.46","730.48","730.5","730.52","730.54","730.56","730.58","730.6","730.62","730.64","730.66","730.68"],"Ask":[30,21,22,0,0,19,9,33,11,28,0,6,0,14,103,54,53,45,161,108,41,58,44,50,22,78,9,67,33,33,14],"Bid":[33,0,0,66,32,0,0,87,34,17,12,0,90,40,132,53,69,110,161,90,61,31,44,19,70,53,24,34,28,0,19],"symbol":"au2506","datetime":"2025-03-31 21:27:00","delta":-243.0,"close":730.0,"open":730.62,"high":730.68,"low":729.96,"volume":2891,"dj":0,"dayma":729.9912820513,"delta累计":2777.0} +{"price":["729.88","729.9","729.92","729.94","729.96","729.98","730.0","730.02","730.04","730.06","730.08","730.1","730.12","730.14","730.16","730.18","730.2","730.22","730.24","730.26","730.28","730.3","730.32","730.34","730.36","730.38","730.4","730.42","730.44","730.46","730.48","730.5","730.52","730.54","730.56"],"Ask":[0,10,13,0,64,87,118,110,57,111,112,72,8,20,14,10,90,29,125,37,12,0,49,42,26,21,39,54,39,40,21,64,68,30,11],"Bid":[28,37,7,20,155,108,142,23,59,112,32,33,52,3,24,45,10,52,13,22,20,14,44,12,46,24,20,37,18,31,38,40,54,23,0],"symbol":"au2506","datetime":"2025-03-31 21:30:00","delta":205.0,"close":730.24,"open":730.0,"high":730.56,"low":729.88,"volume":3250,"dj":0,"dayma":729.9975,"delta累计":2982.0} +{"price":["728.6","728.62","728.64","728.66","728.68","728.7","728.72","728.74","728.76","728.78","728.8","728.82","728.84","728.86","728.88","728.9","728.92","728.94","728.96","728.98","729.0","729.02","729.04","729.08","729.1","729.12","729.14","729.16","729.18","729.2","729.24","729.26","729.28","729.3","729.32","729.34","729.36","729.38","729.4","729.42","729.44","729.46","729.48","729.5","729.52","729.54","729.58","729.6","729.62","729.66","729.68","729.8","729.86","729.9","729.92","730.0","730.08","730.1","730.12","730.14","730.16","730.18"],"Ask":[69,35,48,0,52,0,51,105,63,79,48,0,21,18,134,53,115,277,28,213,212,243,21,0,39,72,23,58,88,41,0,122,33,22,91,79,58,77,9,107,0,28,305,115,137,8,0,0,23,26,0,0,0,0,0,0,0,13,0,12,107,35],"Bid":[29,84,0,37,0,29,105,82,91,82,32,45,23,214,245,218,162,270,320,157,159,243,63,70,0,93,0,33,65,0,81,52,0,53,51,189,66,52,111,155,81,53,137,65,31,53,72,17,54,0,67,15,60,40,28,36,9,19,5,51,18,0],"symbol":"au2506","datetime":"2025-03-31 21:33:00","delta":-1059.0,"close":728.86,"open":730.24,"high":730.24,"low":728.6,"volume":9961,"dj":-5,"dayma":729.9697560976,"delta累计":1923.0} +{"price":["728.2","728.22","728.24","728.26","728.28","728.3","728.32","728.36","728.38","728.4","728.42","728.44","728.46","728.48","728.5","728.52","728.54","728.56","728.58","728.6","728.62","728.64","728.66","728.68","728.7","728.72","728.74","728.76","728.78","728.8","728.82","728.84","728.86","728.88","728.9","728.92","728.94"],"Ask":[32,44,74,85,50,182,0,28,0,135,105,128,204,170,248,262,161,163,27,139,185,29,53,233,166,75,0,0,78,46,19,7,11,40,63,42,18],"Bid":[42,0,69,0,64,152,79,26,45,178,176,38,194,144,289,270,92,16,71,236,121,167,98,40,38,72,25,56,85,44,31,138,9,23,27,8,0],"symbol":"au2506","datetime":"2025-03-31 21:36:00","delta":139.0,"close":728.42,"open":728.88,"high":728.94,"low":728.2,"volume":8080,"dj":0,"dayma":729.9328571429,"delta累计":2062.0} +{"price":["728.06","728.1","728.12","728.14","728.18","728.2","728.22","728.24","728.26","728.28","728.3","728.32","728.34","728.36","728.38","728.4","728.42","728.44","728.46","728.48","728.5","728.52","728.54","728.56","728.58","728.6","728.62","728.64","728.66","728.68","728.7","728.72","728.76"],"Ask":[0,128,31,80,84,114,25,128,14,30,102,61,83,179,72,89,35,35,67,208,19,71,58,91,66,122,73,138,79,171,101,124,62],"Bid":[20,161,7,47,55,125,53,118,10,47,142,33,81,65,134,10,141,201,58,52,171,73,184,77,174,97,109,135,91,55,40,38,0],"symbol":"au2506","datetime":"2025-03-31 21:39:00","delta":-64.0,"close":728.4,"open":728.38,"high":728.76,"low":728.06,"volume":6378,"dj":0,"dayma":729.8972093023,"delta累计":1998.0} +{"price":["727.38","727.4","727.42","727.44","727.46","727.48","727.5","727.52","727.54","727.56","727.58","727.6","727.62","727.64","727.66","727.68","727.7","727.72","727.74","727.76","727.78","727.8","727.82","727.84","727.86","727.88","727.9","727.92","727.94","727.96","727.98","728.04","728.06","728.08","728.1","728.12","728.14","728.16","728.2","728.24","728.26","728.28","728.3","728.32","728.34","728.36","728.38","728.4","728.42","728.44","728.46","728.48","728.5","728.52","728.54","728.56","728.58","728.6","728.62","728.64","728.66","728.68","728.7"],"Ask":[0,0,0,0,13,69,16,80,36,50,25,35,149,108,319,70,16,50,0,0,21,21,0,29,19,196,92,81,0,66,0,0,0,35,19,55,21,22,0,24,0,0,32,32,56,59,42,65,31,0,0,59,26,24,68,24,17,0,23,0,69,36,36],"Bid":[49,28,23,30,32,48,71,83,103,90,87,293,80,146,109,45,78,13,43,49,49,204,77,67,128,207,24,26,68,0,134,23,16,176,52,33,30,27,53,55,4,8,44,29,36,17,39,70,19,14,10,14,45,6,21,9,0,21,0,57,21,119,0],"symbol":"au2506","datetime":"2025-03-31 21:42:00","delta":-1116.0,"close":727.38,"open":728.4,"high":728.7,"low":727.38,"volume":6733,"dj":-1,"dayma":729.84,"delta累计":882.0} +{"price":["726.84","726.9","726.92","726.98","727.0","727.02","727.04","727.06","727.08","727.1","727.12","727.14","727.16","727.18","727.2","727.22","727.24","727.26","727.28","727.3","727.32","727.34","727.36","727.38","727.4","727.42","727.44","727.46","727.48","727.5","727.52","727.56","727.58","727.6","727.62","727.64","727.66","727.68","727.7","727.72","727.74"],"Ask":[0,43,88,29,9,102,11,73,7,94,61,0,208,98,121,97,118,147,40,178,32,172,58,58,248,76,287,38,92,86,32,0,87,34,0,11,49,35,130,123,35],"Bid":[52,109,0,119,88,246,30,2,70,39,39,162,290,48,69,86,74,116,141,236,130,240,165,38,207,61,106,44,64,21,71,61,74,49,10,24,73,33,93,56,0],"symbol":"au2506","datetime":"2025-03-31 21:45:00","delta":-429.0,"close":726.98,"open":727.42,"high":727.74,"low":726.84,"volume":7554,"dj":0,"dayma":729.7764444444,"delta累计":453.0} +{"price":["726.2","726.24","726.26","726.28","726.3","726.32","726.34","726.36","726.38","726.4","726.42","726.44","726.46","726.48","726.5","726.54","726.56","726.58","726.6","726.62","726.64","726.66","726.68","726.7","726.72","726.74","726.76","726.78","726.8","726.82","726.84","726.86","726.88","726.9","726.92","726.94","726.96","726.98","727.06","727.12","727.14","727.18","727.2","727.22","727.24","727.26","727.28","727.3","727.32","727.34","727.36","727.38","727.4","727.42","727.44","727.48","727.5","727.54","727.56","727.58","727.6"],"Ask":[82,0,0,72,87,27,75,25,49,44,76,93,89,33,0,152,56,101,85,35,50,22,111,65,0,95,96,119,230,127,231,37,233,11,121,28,57,39,59,25,23,20,0,103,32,0,131,151,265,89,160,69,76,18,103,140,145,19,33,28,21],"Bid":[31,109,68,0,50,19,118,0,97,50,89,55,116,30,18,25,36,11,37,0,10,0,81,138,54,18,217,291,153,269,79,177,107,47,169,0,35,0,0,0,0,38,75,164,46,134,139,164,115,145,59,47,23,65,35,123,239,103,49,0,0],"symbol":"au2506","datetime":"2025-03-31 21:48:00","delta":-4.0,"close":727.22,"open":726.96,"high":727.6,"low":726.2,"volume":10308,"dj":2,"dayma":729.7208695652,"delta累计":449.0} +{"price":["726.92","726.94","726.96","726.98","727.0","727.02","727.06","727.08","727.1","727.12","727.14","727.16","727.18","727.2","727.22","727.24","727.26","727.28","727.3","727.32","727.34","727.4","727.42","727.48","727.5","727.54","727.56","727.58","727.6","727.62","727.64","727.66","727.68","727.7","727.72","727.74","727.76","727.78","727.8","727.82","727.84","727.86","727.88","727.9","727.92","727.94","727.96","727.98","728.0","728.02","728.04"],"Ask":[0,0,38,0,72,13,54,47,0,0,57,45,147,77,65,105,36,60,27,44,8,58,24,40,0,11,69,30,129,61,132,187,79,48,113,91,11,70,83,37,80,130,71,371,215,108,57,140,58,23,32],"Bid":[2,47,25,53,51,120,64,0,17,49,27,85,45,54,155,21,108,17,0,15,0,0,0,36,31,32,56,78,137,139,47,131,169,23,64,48,132,0,75,90,4,0,383,146,173,145,45,13,57,65,17],"symbol":"au2506","datetime":"2025-03-31 21:51:00","delta":162.0,"close":728.06,"open":727.24,"high":728.06,"low":726.92,"volume":7669,"dj":1,"dayma":729.6855319149,"delta累计":611.0} +{"price":["728.06","728.08","728.1","728.12","728.14","728.16","728.18","728.2","728.22","728.24","728.26","728.28","728.3","728.32","728.34","728.36","728.38","728.4","728.42","728.44","728.46","728.48","728.5","728.52","728.54","728.56","728.58","728.6","728.62","728.64","728.66","728.68","728.7","728.72","728.74","728.76","728.78","728.8","728.82","728.86","728.88","728.9","728.92","728.96","729.0","729.02"],"Ask":[8,22,21,91,5,51,91,52,36,30,55,330,64,110,22,79,56,65,74,0,54,17,161,160,67,92,50,117,75,118,88,65,143,70,106,65,157,87,60,7,28,55,0,14,48,18],"Bid":[0,31,23,31,46,40,25,81,42,37,51,46,34,13,92,42,54,85,0,25,59,74,201,105,143,151,26,136,10,21,188,181,60,228,76,358,115,11,0,23,0,97,58,0,0,0],"symbol":"au2506","datetime":"2025-03-31 21:54:00","delta":65.0,"close":729.02,"open":728.06,"high":729.02,"low":728.06,"volume":7064,"dj":0,"dayma":729.6716666667,"delta累计":676.0} +{"price":["728.92","728.94","728.96","728.98","729.0","729.02","729.04","729.06","729.08","729.1","729.12","729.14","729.16","729.18","729.2","729.22","729.24","729.26","729.28","729.3","729.32","729.34","729.36","729.38","729.4","729.42","729.44","729.46","729.48"],"Ask":[16,57,47,20,107,21,88,142,30,54,55,140,36,80,323,166,175,45,53,24,76,31,45,93,239,174,43,0,27],"Bid":[44,63,0,23,92,101,90,99,79,50,77,42,11,114,243,377,75,24,32,51,14,33,87,194,132,82,33,23,0],"symbol":"au2506","datetime":"2025-03-31 21:57:00","delta":122.0,"close":729.4,"open":729.04,"high":729.48,"low":728.92,"volume":5262,"dj":0,"dayma":729.666122449,"delta累计":798.0} +{"price":["729.3","729.32","729.34","729.36","729.38","729.4","729.42","729.44","729.46","729.48","729.5","729.52","729.54","729.56","729.58","729.6","729.62","729.64","729.66","729.68","729.7"],"Ask":[0,24,51,50,29,90,138,133,49,98,115,108,216,144,72,185,68,76,21,39,68],"Bid":[10,44,52,108,52,213,78,38,78,79,260,151,117,93,196,143,121,80,0,25,17],"symbol":"au2506","datetime":"2025-03-31 22:00:00","delta":-181.0,"close":729.6,"open":729.42,"high":729.7,"low":729.3,"volume":4164,"dj":0,"dayma":729.6648,"delta累计":617.0} +{"price":["729.14","729.16","729.18","729.2","729.22","729.24","729.26","729.3","729.34","729.36","729.38","729.4","729.42","729.44","729.46","729.48","729.5","729.52","729.54","729.56","729.58","729.6","729.62","729.64","729.66","729.68","729.7","729.72","729.74","729.76","729.78","729.8"],"Ask":[0,44,18,139,0,75,19,0,37,71,100,16,36,39,86,6,116,93,168,93,66,136,142,134,120,66,90,65,150,24,64,41],"Bid":[40,136,146,25,58,73,42,15,2,78,116,87,69,48,59,24,164,156,223,70,82,156,131,100,65,78,15,57,155,0,6,0],"symbol":"au2506","datetime":"2025-03-31 22:03:00","delta":-222.0,"close":729.5,"open":729.58,"high":729.8,"low":729.14,"volume":5258,"dj":0,"dayma":729.6615686275,"delta累计":395.0} +{"price":["729.32","729.34","729.36","729.38","729.4","729.42","729.44","729.46","729.48","729.5","729.52","729.54","729.56","729.58","729.6","729.62","729.64","729.66","729.68","729.7","729.72","729.74","729.76","729.78","729.8","729.86","729.88","729.9","729.92","729.94","729.96","729.98","730.0"],"Ask":[30,22,40,17,95,106,12,85,80,75,62,82,106,149,87,77,19,61,57,0,50,27,48,22,22,35,44,26,22,36,25,16,20],"Bid":[45,41,87,129,83,52,41,57,80,52,110,81,136,155,108,47,25,0,0,30,21,0,88,0,74,36,158,0,20,159,0,0,0],"symbol":"au2506","datetime":"2025-03-31 22:06:00","delta":-260.0,"close":729.54,"open":729.58,"high":730.0,"low":729.32,"volume":4043,"dj":0,"dayma":729.6592307692,"delta累计":135.0} +{"price":["729.56","729.58","729.6","729.62","729.64","729.66","729.68","729.7","729.72","729.74","729.76","729.78","729.82","729.84","729.86","729.88","729.9","729.92","729.94","729.96","729.98","730.0","730.02","730.04","730.06","730.08","730.1","730.12","730.14","730.16","730.18","730.2","730.22","730.24"],"Ask":[0,52,77,66,83,28,16,28,9,0,15,18,7,20,0,25,180,50,68,122,5,93,28,138,90,158,234,37,60,40,64,121,40,10],"Bid":[21,33,65,54,3,55,13,0,0,21,4,19,0,2,54,44,126,47,4,42,50,61,23,123,297,101,11,85,17,23,66,64,16,18],"symbol":"au2506","datetime":"2025-03-31 22:09:00","delta":420.0,"close":730.08,"open":729.58,"high":730.24,"low":729.56,"volume":3930,"dj":0,"dayma":729.6671698113,"delta累计":555.0} +{"price":["730.06","730.08","730.12","730.14","730.16","730.18","730.2","730.22","730.24","730.26","730.28","730.3","730.32","730.34","730.36","730.38","730.4","730.42"],"Ask":[0,13,97,36,109,194,111,129,173,244,223,169,136,21,65,0,19,7],"Bid":[16,82,35,123,113,82,139,177,273,322,176,182,35,119,51,19,11,0],"symbol":"au2506","datetime":"2025-03-31 22:12:00","delta":-209.0,"close":730.28,"open":730.08,"high":730.42,"low":730.06,"volume":4072,"dj":0,"dayma":729.6785185185,"delta累计":346.0} +{"price":["729.94","729.96","729.98","730.0","730.02","730.04","730.06","730.08","730.1","730.12","730.14","730.16","730.18","730.2","730.22","730.24","730.26","730.28","730.3","730.32","730.34","730.36","730.38","730.4","730.42"],"Ask":[0,17,24,34,19,17,67,59,15,48,56,86,123,47,119,59,122,69,59,85,41,79,29,66,0],"Bid":[6,33,102,97,6,46,63,36,93,54,48,73,102,141,73,146,35,31,114,48,77,32,140,17,13],"symbol":"au2506","datetime":"2025-03-31 22:15:00","delta":-286.0,"close":730.1,"open":730.34,"high":730.42,"low":729.94,"volume":3163,"dj":0,"dayma":729.6861818182,"delta累计":60.0} +{"price":["729.4","729.42","729.44","729.46","729.48","729.5","729.52","729.54","729.56","729.6","729.62","729.64","729.68","729.7","729.72","729.74","729.76","729.78","729.8","729.82","729.84","729.86","729.88","729.9","729.92","729.94","729.96","729.98","730.0","730.02","730.04","730.06","730.08","730.1","730.12","730.14","730.16","730.18","730.2","730.22","730.24","730.26","730.28","730.3","730.32","730.34","730.36","730.38","730.4"],"Ask":[45,44,83,31,133,17,69,61,48,35,9,6,0,73,9,16,18,18,70,3,53,21,8,25,12,40,51,90,71,37,34,45,47,42,60,0,62,67,23,65,96,89,25,57,83,28,68,12,25],"Bid":[44,0,0,122,221,352,46,48,63,38,39,0,59,41,17,21,15,59,128,6,48,42,0,0,32,71,64,60,142,4,44,5,36,6,9,15,41,98,34,42,56,31,86,77,17,18,111,0,0],"symbol":"au2506","datetime":"2025-03-31 22:18:00","delta":-384.0,"close":729.8,"open":730.08,"high":730.4,"low":729.4,"volume":4954,"dj":0,"dayma":729.6882142857,"delta累计":-324.0} +{"price":["729.34","729.36","729.38","729.4","729.42","729.44","729.46","729.48","729.5","729.52","729.54","729.56","729.58","729.6","729.62","729.64","729.66","729.68","729.7","729.72","729.74","729.76","729.78","729.8","729.82","729.84","729.86","729.88","729.92"],"Ask":[24,31,65,98,52,110,43,144,106,129,16,70,18,8,56,56,38,8,52,46,42,8,0,13,24,2,15,18,10],"Bid":[30,78,89,150,78,57,122,110,65,33,15,54,35,48,52,84,54,50,117,11,0,0,11,22,5,5,7,29,0],"symbol":"au2506","datetime":"2025-03-31 22:21:00","delta":-109.0,"close":729.38,"open":729.8,"high":729.92,"low":729.34,"volume":2992,"dj":0,"dayma":729.6828070175,"delta累计":-433.0} +{"price":["729.24","729.26","729.28","729.3","729.32","729.34","729.36","729.38","729.4","729.42","729.44","729.46","729.48","729.5","729.52","729.54","729.56","729.58","729.6","729.62","729.64","729.66","729.68","729.7","729.72","729.74","729.76","729.78","729.8","729.82","729.84","729.88"],"Ask":[0,17,0,15,162,36,102,67,47,27,43,35,55,81,54,20,83,27,25,43,31,49,28,10,17,16,51,73,54,38,4,4],"Bid":[15,57,52,48,138,26,87,75,45,47,63,76,26,124,5,36,90,79,21,8,36,77,50,6,32,41,87,48,23,15,11,0],"symbol":"au2506","datetime":"2025-03-31 22:24:00","delta":-230.0,"close":729.36,"open":729.4,"high":729.88,"low":729.24,"volume":3226,"dj":0,"dayma":729.6772413793,"delta累计":-663.0} +{"price":["729.22","729.24","729.26","729.28","729.3","729.32","729.34","729.36","729.38","729.4","729.42","729.44","729.46","729.48","729.5"],"Ask":[0,5,26,64,27,74,106,61,59,95,121,63,21,36,10],"Bid":[16,53,76,17,66,47,60,96,70,74,198,33,18,14,0],"symbol":"au2506","datetime":"2025-03-31 22:27:00","delta":-70.0,"close":729.34,"open":729.38,"high":729.5,"low":729.22,"volume":1783,"dj":0,"dayma":729.6715254237,"delta累计":-733.0} +{"price":["729.36","729.38","729.42","729.44","729.46","729.48","729.5","729.52","729.54","729.56","729.58","729.6","729.62","729.64","729.66","729.68","729.7","729.72","729.74","729.76","729.78","729.8","729.82","729.84","729.86","729.88","729.9","729.92","729.94","729.96","729.98","730.0","730.02"],"Ask":[4,10,7,68,2,58,23,142,60,43,4,0,48,21,0,47,2,43,51,34,26,96,62,78,156,69,78,104,92,51,32,101,6],"Bid":[0,0,8,26,27,36,20,42,9,17,8,14,2,22,55,6,0,19,27,45,65,86,162,120,122,75,83,47,22,6,19,35,8],"symbol":"au2506","datetime":"2025-03-31 22:30:00","delta":385.0,"close":729.8,"open":729.36,"high":730.02,"low":729.36,"volume":3068,"dj":1,"dayma":729.6736666667,"delta累计":-348.0} +{"price":["729.5","729.52","729.54","729.56","729.58","729.6","729.62","729.64","729.66","729.68","729.7","729.72","729.74","729.76","729.78","729.8","729.82","729.84","729.86","729.88","729.9","729.92","729.94","729.96","729.98","730.0","730.02","730.04","730.06","730.08","730.1","730.12","730.14","730.16","730.18"],"Ask":[0,0,107,31,10,33,116,9,13,16,25,0,4,33,28,16,31,26,33,39,68,46,56,8,49,118,77,146,25,41,57,32,22,13,18],"Bid":[31,44,35,14,29,16,36,17,7,32,8,9,5,13,4,23,26,3,37,74,96,22,39,34,70,135,47,79,63,9,113,35,38,4,0],"symbol":"au2506","datetime":"2025-03-31 22:33:00","delta":99.0,"close":730.14,"open":729.76,"high":730.18,"low":729.5,"volume":2883,"dj":0,"dayma":729.6813114754,"delta累计":-249.0} +{"price":["730.2","730.22","730.24","730.26","730.28","730.3","730.32","730.34","730.36","730.38","730.4","730.42","730.44","730.46","730.48","730.5","730.52","730.54","730.56","730.58","730.6","730.62","730.64","730.66","730.68","730.7","730.72","730.74","730.76","730.78","730.8","730.82","730.84","730.86","730.88","730.92","730.96","730.98","731.0","731.02","731.04","731.06","731.08","731.1","731.12","731.14","731.16","731.18","731.2","731.24","731.26","731.28","731.3","731.32","731.36","731.38","731.4","731.42","731.44"],"Ask":[28,42,0,42,47,64,26,8,8,47,34,26,4,0,30,48,65,7,115,19,138,0,108,71,14,51,15,0,65,52,10,31,51,20,29,0,10,24,275,67,166,63,160,141,126,91,49,100,176,7,24,27,61,42,18,18,27,62,13],"Bid":[0,0,38,27,19,15,6,25,13,35,15,17,0,39,0,23,31,24,4,28,8,56,30,54,57,115,65,14,41,0,24,10,35,10,0,10,33,51,158,82,98,151,42,206,37,41,18,35,20,0,0,69,57,0,0,0,62,24,0],"symbol":"au2506","datetime":"2025-03-31 22:36:00","delta":990.0,"close":731.44,"open":730.2,"high":731.44,"low":730.2,"volume":5606,"dj":2,"dayma":729.7096774194,"delta累计":741.0} +{"price":["730.88","730.9","730.92","730.94","730.96","730.98","731.0","731.02","731.04","731.06","731.08","731.1","731.12","731.14","731.16","731.18","731.2","731.22","731.24","731.26","731.28","731.3","731.32","731.34","731.36","731.38","731.4","731.42","731.44","731.46","731.48","731.5"],"Ask":[0,21,33,186,79,142,79,35,91,0,28,10,29,7,53,43,4,105,43,35,33,37,5,0,40,83,153,59,137,130,50,27],"Bid":[22,37,172,159,74,47,24,27,32,25,31,8,79,113,18,33,41,26,104,1,0,14,3,40,80,68,116,153,74,71,70,0],"symbol":"au2506","datetime":"2025-03-31 22:39:00","delta":15.0,"close":731.24,"open":731.46,"high":731.5,"low":730.88,"volume":3982,"dj":0,"dayma":729.733968254,"delta累计":756.0} +{"price":["731.0","731.02","731.04","731.06","731.08","731.1","731.12","731.14","731.16","731.18","731.2","731.22","731.24","731.26","731.28","731.3","731.32","731.34","731.36","731.38","731.4","731.42","731.44","731.46","731.48","731.5","731.52","731.54","731.56","731.58","731.6","731.62","731.64","731.66","731.7","731.72","731.74"],"Ask":[0,0,12,59,73,40,72,88,62,135,74,61,6,76,12,31,27,13,28,16,57,46,111,22,73,73,88,30,31,0,20,16,26,43,36,30,24],"Bid":[12,60,66,101,83,64,61,46,99,34,48,45,45,0,0,0,14,7,16,0,0,48,72,8,27,33,67,5,30,41,61,15,90,55,45,14,0],"symbol":"au2506","datetime":"2025-03-31 22:42:00","delta":199.0,"close":731.5,"open":731.26,"high":731.74,"low":731.0,"volume":3285,"dj":1,"dayma":729.7615625,"delta累计":955.0} +{"price":["731.14","731.16","731.18","731.2","731.22","731.24","731.26","731.28","731.3","731.32","731.34","731.36","731.38","731.4","731.42","731.44","731.46","731.48","731.5","731.52","731.54"],"Ask":[12,40,6,69,69,23,48,3,44,84,75,18,79,53,17,27,16,45,6,35,16],"Bid":[61,40,22,37,67,35,26,23,76,62,73,55,47,53,65,21,27,40,7,0,0],"symbol":"au2506","datetime":"2025-03-31 22:45:00","delta":-52.0,"close":731.16,"open":731.52,"high":731.54,"low":731.14,"volume":1780,"dj":0,"dayma":729.7830769231,"delta累计":903.0} +{"price":["731.16","731.18","731.2","731.22","731.24","731.26","731.28","731.3","731.32","731.34","731.36","731.38","731.4","731.42","731.44","731.46","731.48","731.5","731.52","731.54","731.56","731.58","731.6","731.62","731.64","731.66","731.68","731.7"],"Ask":[18,7,5,2,6,34,32,57,60,145,48,107,52,156,81,15,31,89,18,22,50,22,0,0,24,65,13,27],"Bid":[14,0,0,8,11,14,9,27,112,87,130,49,70,84,23,32,46,11,8,5,0,40,3,33,0,41,16,0],"symbol":"au2506","datetime":"2025-03-31 22:48:00","delta":313.0,"close":731.44,"open":731.16,"high":731.7,"low":731.16,"volume":2239,"dj":0,"dayma":729.8081818182,"delta累计":1216.0} +{"price":["731.28","731.3","731.32","731.34","731.36","731.38","731.4","731.42","731.44","731.46","731.48","731.5","731.52","731.54","731.56","731.58","731.6","731.62","731.64","731.66","731.68","731.7","731.72","731.74","731.76","731.78","731.8","731.82","731.84","731.86","731.88","731.9","731.92","731.94","731.96"],"Ask":[0,9,30,24,43,31,97,3,17,29,66,33,104,49,27,69,29,1,18,55,0,82,21,60,22,54,30,3,107,37,80,0,48,41,72],"Bid":[19,13,29,33,24,38,31,12,21,35,74,40,86,35,78,0,66,15,0,6,29,42,13,33,36,11,11,27,0,22,74,135,61,0,14],"symbol":"au2506","datetime":"2025-03-31 22:51:00","delta":228.0,"close":731.88,"open":731.44,"high":731.96,"low":731.28,"volume":2726,"dj":1,"dayma":729.8391044776,"delta累计":1444.0} +{"price":["731.32","731.34","731.36","731.38","731.4","731.42","731.44","731.46","731.48","731.5","731.52","731.54","731.56","731.58","731.6","731.62","731.64","731.66","731.68","731.7","731.74","731.76","731.78","731.8","731.82","731.84","731.86","731.88","731.9","731.92","731.94"],"Ask":[0,0,12,29,53,49,23,6,5,3,32,10,47,62,18,26,48,34,80,23,0,18,11,50,40,46,19,9,62,74,11],"Bid":[52,18,86,32,80,9,12,37,52,16,51,72,35,76,48,28,36,58,31,70,6,37,115,60,76,52,85,69,58,26,0],"symbol":"au2506","datetime":"2025-03-31 22:54:00","delta":-583.0,"close":731.44,"open":731.86,"high":731.94,"low":731.32,"volume":2692,"dj":0,"dayma":729.8626470588,"delta累计":861.0} +{"price":["731.34","731.36","731.38","731.4","731.42","731.44","731.46","731.48","731.5","731.52","731.54","731.56","731.58","731.6","731.62","731.64","731.66"],"Ask":[7,3,12,21,14,13,45,60,56,33,2,54,121,39,92,40,134],"Bid":[10,43,62,10,30,56,58,41,74,43,49,34,76,62,23,45,33],"symbol":"au2506","datetime":"2025-03-31 22:57:00","delta":-3.0,"close":731.58,"open":731.48,"high":731.66,"low":731.34,"volume":1580,"dj":0,"dayma":729.8875362319,"delta累计":858.0} +{"price":["731.58","731.6","731.62","731.64","731.66","731.68","731.7","731.72","731.74","731.76","731.78","731.8","731.82","731.84","731.86","731.88","731.9"],"Ask":[0,7,11,4,36,46,128,31,94,133,158,185,16,15,85,60,36],"Bid":[4,0,0,37,36,48,83,53,99,78,148,151,33,111,65,20,0],"symbol":"au2506","datetime":"2025-03-31 23:00:00","delta":79.0,"close":731.8,"open":731.6,"high":731.9,"low":731.58,"volume":2120,"dj":0,"dayma":729.9148571429,"delta累计":937.0} +{"price":["731.62","731.64","731.66","731.68","731.7","731.72","731.74","731.76","731.78","731.8","731.82","731.84","731.86","731.88","731.9","731.92"],"Ask":[0,0,29,48,72,75,125,108,125,91,19,19,153,142,52,13],"Bid":[28,40,42,65,84,105,177,182,59,81,49,57,27,35,0,0],"symbol":"au2506","datetime":"2025-03-31 23:03:00","delta":40.0,"close":731.78,"open":731.8,"high":731.92,"low":731.62,"volume":2287,"dj":0,"dayma":729.9411267606,"delta累计":977.0} +{"price":["731.18","731.2","731.22","731.24","731.26","731.28","731.3","731.32","731.34","731.36","731.38","731.4","731.42","731.44","731.46","731.48","731.5","731.52","731.54","731.56","731.58","731.6","731.62","731.64","731.66","731.68","731.7","731.72","731.74","731.76","731.8"],"Ask":[0,42,57,97,13,32,71,0,84,9,8,4,0,11,0,0,0,31,48,28,35,57,42,57,59,31,32,31,10,2,2],"Bid":[105,41,40,53,33,46,132,48,6,15,15,26,42,10,9,17,13,58,38,72,4,87,41,86,43,32,25,9,9,6,0],"symbol":"au2506","datetime":"2025-03-31 23:06:00","delta":-268.0,"close":731.3,"open":731.8,"high":731.8,"low":731.18,"volume":2187,"dj":-4,"dayma":729.96,"delta累计":709.0} +{"price":["731.0","731.02","731.04","731.06","731.08","731.1","731.12","731.14","731.16","731.18","731.2","731.22","731.24","731.26","731.28","731.3","731.32","731.34","731.36","731.38","731.4"],"Ask":[0,0,72,41,12,19,40,29,42,15,32,107,66,82,37,119,136,80,28,32,7],"Bid":[5,17,76,138,13,15,5,16,13,16,79,58,145,43,59,64,102,37,6,10,9],"symbol":"au2506","datetime":"2025-03-31 23:09:00","delta":70.0,"close":731.24,"open":731.32,"high":731.4,"low":731.0,"volume":2146,"dj":0,"dayma":729.9775342466,"delta累计":779.0} +{"price":["731.22","731.24","731.26","731.28","731.3","731.32","731.34","731.36","731.38","731.44","731.46","731.48","731.5","731.52","731.54","731.56","731.58","731.6","731.62","731.64","731.66","731.68","731.7","731.72","731.74","731.76","731.78","731.8"],"Ask":[0,10,20,0,4,13,129,49,11,38,0,11,9,11,13,16,35,67,3,64,20,101,89,102,87,45,25,6],"Bid":[7,35,0,4,73,28,49,0,0,0,17,0,0,14,40,24,64,38,11,45,48,83,86,51,25,13,76,25],"symbol":"au2506","datetime":"2025-03-31 23:12:00","delta":122.0,"close":731.66,"open":731.24,"high":731.8,"low":731.22,"volume":1964,"dj":0,"dayma":730.0002702703,"delta累计":901.0} +{"price":["731.64","731.66","731.68","731.7","731.72","731.74","731.76","731.78","731.8","731.82","731.84","731.88","731.98","732.1","732.28","732.3","732.32","732.34","732.36","732.38","732.4","732.42","732.44","732.46","732.48","732.5","732.52","732.54","732.56","732.58","732.6","732.62","732.64"],"Ask":[0,7,11,10,21,2,45,37,67,54,12,133,55,427,35,0,0,309,70,58,84,105,137,122,149,155,187,66,126,91,113,13,57],"Bid":[3,21,0,32,0,23,15,24,16,0,0,0,0,0,24,15,69,128,69,138,304,223,128,136,200,161,117,45,190,26,54,0,0],"symbol":"au2506","datetime":"2025-03-31 23:15:00","delta":597.0,"close":732.28,"open":731.66,"high":732.64,"low":731.64,"volume":5255,"dj":4,"dayma":730.0306666667,"delta累计":1498.0} +{"price":["731.96","731.98","732.0","732.02","732.04","732.06","732.08","732.1","732.12","732.14","732.16","732.18","732.2","732.22","732.24","732.26","732.28","732.3","732.32","732.34"],"Ask":[0,8,13,33,79,72,54,183,38,17,7,33,19,96,77,110,130,13,35,41],"Bid":[33,27,15,12,53,61,136,87,40,11,63,77,87,93,97,111,68,10,0,11],"symbol":"au2506","datetime":"2025-03-31 23:18:00","delta":-34.0,"close":732.2,"open":732.28,"high":732.34,"low":731.96,"volume":2437,"dj":0,"dayma":730.0592105263,"delta累计":1464.0} +{"price":["731.6","731.62","731.64","731.66","731.68","731.7","731.72","731.74","731.76","731.78","731.8","731.82","731.84","731.86","731.88","731.9","731.92","731.96","731.98","732.0","732.02","732.04","732.06","732.08","732.1","732.12","732.14","732.16","732.18","732.2","732.22","732.24","732.26","732.28","732.3","732.32"],"Ask":[0,10,6,24,4,25,30,88,23,25,4,48,17,36,93,13,33,7,10,0,0,0,13,55,34,35,10,19,0,25,38,7,19,22,39,2],"Bid":[24,0,35,23,42,92,102,64,11,16,36,17,28,32,105,15,8,18,0,52,11,7,53,95,30,37,51,13,9,7,24,0,0,25,11,0],"symbol":"au2506","datetime":"2025-03-31 23:21:00","delta":-279.0,"close":731.92,"open":732.2,"high":732.32,"low":731.6,"volume":2066,"dj":0,"dayma":730.0833766234,"delta累计":1185.0} +{"price":["731.74","731.76","731.8","731.82","731.86","731.88","731.9","731.92","731.94","731.96","731.98","732.0","732.02","732.04","732.06","732.08","732.1","732.12","732.14","732.16","732.18"],"Ask":[5,22,7,6,9,8,9,25,20,14,36,70,67,56,47,56,22,21,32,55,23],"Bid":[13,10,12,4,9,53,38,17,14,24,46,21,79,51,89,56,4,37,66,31,15],"symbol":"au2506","datetime":"2025-03-31 23:24:00","delta":-79.0,"close":732.0,"open":731.92,"high":732.18,"low":731.74,"volume":1449,"dj":0,"dayma":730.1079487179,"delta累计":1106.0} +{"price":["731.5","731.54","731.56","731.58","731.6","731.62","731.64","731.66","731.68","731.7","731.72","731.74","731.76","731.78","731.8","731.84","731.86","731.88","731.9","731.92","731.94","731.96","731.98","732.0","732.02","732.04","732.06","732.08","732.1"],"Ask":[0,26,11,40,4,51,58,25,3,29,35,16,24,31,89,0,0,12,18,26,4,33,62,42,1,43,59,84,33],"Bid":[5,33,22,34,53,37,25,4,27,74,3,13,44,50,53,11,33,37,37,13,4,51,15,59,16,15,53,19,6],"symbol":"au2506","datetime":"2025-03-31 23:27:00","delta":13.0,"close":731.56,"open":732.02,"high":732.1,"low":731.5,"volume":1797,"dj":0,"dayma":730.1263291139,"delta累计":1119.0} +{"price":["731.22","731.24","731.26","731.28","731.3","731.32","731.34","731.36","731.38","731.4","731.42","731.44","731.46","731.48","731.5","731.52","731.54","731.56","731.58"],"Ask":[0,16,0,45,87,42,28,109,37,82,51,76,89,137,90,11,0,46,31],"Bid":[14,24,6,44,79,92,73,60,43,95,61,117,63,111,49,38,69,14,13],"symbol":"au2506","datetime":"2025-03-31 23:30:00","delta":-88.0,"close":731.26,"open":731.56,"high":731.58,"low":731.22,"volume":2200,"dj":0,"dayma":730.1405,"delta累计":1031.0} +{"price":["730.86","730.88","730.9","730.92","730.94","730.96","730.98","731.0","731.02","731.04","731.06","731.08","731.1","731.12","731.14","731.16","731.18","731.2","731.22","731.24","731.26","731.28","731.3"],"Ask":[0,11,45,17,42,46,18,61,29,70,84,86,41,47,13,67,91,5,37,52,54,64,33],"Bid":[25,0,126,30,41,74,60,61,44,73,59,195,61,39,71,40,20,46,30,22,12,36,21],"symbol":"au2506","datetime":"2025-03-31 23:33:00","delta":-173.0,"close":731.06,"open":731.24,"high":731.3,"low":730.86,"volume":2323,"dj":0,"dayma":730.1518518519,"delta累计":858.0} +{"price":["730.82","730.84","730.86","730.88","730.9","730.94","730.96","730.98","731.0","731.02","731.04","731.06","731.08","731.1","731.12","731.14","731.16","731.18","731.2","731.22"],"Ask":[0,22,0,26,4,46,14,12,59,57,36,77,73,102,75,82,103,6,7,20],"Bid":[10,7,6,28,3,12,24,8,73,101,56,54,73,97,82,32,45,12,12,0],"symbol":"au2506","datetime":"2025-03-31 23:36:00","delta":86.0,"close":730.82,"open":731.06,"high":731.22,"low":730.82,"volume":1641,"dj":0,"dayma":730.16,"delta累计":944.0} +{"price":["729.98","730.0","730.02","730.04","730.06","730.08","730.1","730.12","730.14","730.16","730.18","730.2","730.22","730.24","730.26","730.28","730.3","730.32","730.34","730.36","730.38","730.4","730.42","730.44","730.46","730.48","730.5","730.52","730.54","730.62","730.64","730.66","730.7","730.72","730.74","730.76","730.78","730.8","730.82"],"Ask":[19,5,249,23,11,12,36,25,33,1,2,24,22,42,84,75,86,8,15,57,163,150,66,98,14,280,78,59,0,0,0,0,0,0,0,0,27,0,25],"Bid":[38,218,249,18,37,22,18,34,53,13,75,0,48,103,92,66,125,77,109,164,265,134,48,105,74,100,28,0,50,19,12,13,21,19,7,26,0,57,0],"symbol":"au2506","datetime":"2025-03-31 23:39:00","delta":-748.0,"close":730.38,"open":730.8,"high":730.82,"low":729.98,"volume":4658,"dj":-6,"dayma":730.1626506024,"delta累计":196.0} +{"price":["730.32","730.34","730.36","730.38","730.4","730.42","730.44","730.46","730.48","730.5","730.52","730.54","730.56","730.58","730.6","730.62","730.64","730.66"],"Ask":[0,27,4,0,91,40,16,52,114,97,58,22,21,15,58,76,102,33],"Bid":[17,36,11,30,52,46,54,87,25,90,35,6,5,26,84,132,41,0],"symbol":"au2506","datetime":"2025-03-31 23:42:00","delta":49.0,"close":730.52,"open":730.38,"high":730.66,"low":730.32,"volume":1713,"dj":0,"dayma":730.1669047619,"delta累计":245.0} +{"price":["730.06","730.08","730.12","730.14","730.16","730.18","730.2","730.22","730.24","730.26","730.28","730.3","730.32","730.34","730.36","730.38","730.4","730.42","730.44","730.46","730.48","730.5","730.52","730.54"],"Ask":[0,24,0,19,0,38,27,11,33,28,24,28,110,35,85,40,42,23,29,2,9,1,24,19],"Bid":[41,0,8,11,47,14,5,30,21,47,18,74,66,41,52,27,28,44,38,0,93,11,7,0],"symbol":"au2506","datetime":"2025-03-31 23:45:00","delta":-72.0,"close":730.38,"open":730.5,"high":730.54,"low":730.06,"volume":1473,"dj":0,"dayma":730.1694117647,"delta累计":173.0} +{"price":["730.3","730.32","730.34","730.36","730.38","730.4","730.42","730.44"],"Ask":[0,10,43,91,158,74,57,35],"Bid":[12,58,52,171,127,70,15,0],"symbol":"au2506","datetime":"2025-03-31 23:48:00","delta":-37.0,"close":730.38,"open":730.38,"high":730.44,"low":730.3,"volume":1028,"dj":0,"dayma":730.1718604651,"delta累计":136.0} +{"price":["730.24","730.26","730.3","730.32","730.34","730.36","730.38","730.4","730.42","730.44","730.46","730.48","730.5","730.52","730.54","730.56","730.58","730.6","730.62","730.64","730.66","730.68","730.7","730.72","730.74","730.76","730.78","730.8"],"Ask":[0,0,13,0,13,5,24,26,35,51,58,68,67,90,70,35,33,0,6,3,9,164,29,5,85,49,116,157],"Bid":[9,25,16,49,12,17,0,12,4,22,52,42,74,32,0,0,0,16,23,1,29,23,79,65,51,92,144,51],"symbol":"au2506","datetime":"2025-03-31 23:51:00","delta":271.0,"close":730.72,"open":730.38,"high":730.8,"low":730.24,"volume":2390,"dj":0,"dayma":730.1781609195,"delta累计":407.0} +{"price":["729.76","729.78","729.8","729.82","729.84","729.86","729.88","729.9","729.92","729.94","729.98","730.0","730.02","730.04","730.06","730.08","730.1","730.12","730.14","730.18","730.2","730.22","730.24","730.26","730.28","730.3","730.32","730.34","730.36","730.38","730.4","730.42","730.44","730.46","730.48","730.5","730.52","730.54","730.56","730.58","730.6","730.62","730.64","730.66","730.68","730.7","730.72","730.74","730.76","730.78"],"Ask":[7,12,87,47,71,18,14,28,0,9,8,54,106,79,60,30,65,18,24,3,25,83,34,22,0,2,13,5,16,10,19,6,0,21,29,6,18,0,0,0,0,28,12,18,15,9,4,19,2,6],"Bid":[57,0,98,70,32,14,55,46,8,30,332,40,136,40,35,44,68,1,0,25,50,36,27,0,3,15,17,14,2,0,37,36,16,18,21,33,5,7,4,4,27,11,19,44,3,0,0,10,4,0],"symbol":"au2506","datetime":"2025-03-31 23:54:00","delta":-432.0,"close":730.24,"open":730.72,"high":730.78,"low":729.76,"volume":2955,"dj":-2,"dayma":730.1788636364,"delta累计":-25.0} +{"price":["730.22","730.24","730.26","730.28","730.3","730.32","730.34","730.36","730.38","730.4","730.42","730.44","730.46","730.48","730.5","730.52","730.54","730.56","730.58","730.6","730.62","730.64"],"Ask":[0,0,38,23,8,2,1,6,54,83,79,148,29,98,11,36,43,94,118,43,38,42],"Bid":[22,36,8,7,2,13,11,71,71,28,131,66,48,30,55,29,79,130,71,0,0,0],"symbol":"au2506","datetime":"2025-03-31 23:57:00","delta":86.0,"close":730.56,"open":730.22,"high":730.64,"low":730.22,"volume":2065,"dj":0,"dayma":730.1831460674,"delta累计":61.0} +{"price":["730.38","730.4","730.42","730.44","730.46","730.48","730.5","730.52","730.54","730.56","730.58","730.6","730.62","730.64","730.66","730.68","730.7","730.72","730.74"],"Ask":[0,11,25,24,53,6,33,20,56,100,195,111,40,85,69,126,52,48,125],"Bid":[9,32,14,25,137,74,42,102,89,200,226,68,31,24,117,85,0,0,0],"symbol":"au2506","datetime":"2025-04-01 00:00:00","delta":-96.0,"close":730.4,"open":730.56,"high":730.74,"low":730.38,"volume":2624,"dj":0,"dayma":730.1855555556,"delta累计":-35.0} +{"price":["730.4","730.44","730.46","730.48","730.5","730.52","730.56","730.58","730.6","730.62","730.64","730.66","730.68","730.7","730.72","730.74","730.76","730.78","730.8","730.82","730.84","730.86","730.88","730.9","730.92","730.94","730.96","730.98","731.0","731.02","731.04","731.06","731.08","731.1"],"Ask":[6,41,18,7,16,6,0,51,54,23,27,14,4,59,40,0,74,19,36,8,40,81,89,21,11,168,25,5,48,174,119,66,33,83],"Bid":[7,1,21,3,0,0,43,15,25,6,8,17,7,0,0,17,52,69,11,14,4,18,56,45,41,57,72,73,63,60,124,42,20,36],"symbol":"au2506","datetime":"2025-04-01 00:03:00","delta":439.0,"close":730.94,"open":730.4,"high":731.1,"low":730.4,"volume":2760,"dj":0,"dayma":730.1938461538,"delta累计":404.0} +{"price":["730.88","730.9","730.92","730.94","730.96","730.98","731.0","731.02","731.04"],"Ask":[0,15,74,50,63,69,55,18,16],"Bid":[3,38,101,85,40,61,11,1,0],"symbol":"au2506","datetime":"2025-04-01 00:06:00","delta":20.0,"close":730.96,"open":730.92,"high":731.04,"low":730.88,"volume":770,"dj":0,"dayma":730.202173913,"delta累计":424.0} +{"price":["730.52","730.54","730.56","730.58","730.6","730.62","730.64","730.66","730.68","730.7","730.72","730.74","730.76","730.78","730.8","730.82","730.84","730.86","730.88","730.9","730.92","730.96"],"Ask":[0,3,24,8,21,51,10,2,0,0,1,27,15,14,37,14,23,17,42,21,10,12],"Bid":[4,19,80,54,6,5,18,13,2,6,17,5,18,19,78,23,17,45,42,20,13,8],"symbol":"au2506","datetime":"2025-04-01 00:09:00","delta":-160.0,"close":730.64,"open":730.92,"high":730.96,"low":730.52,"volume":921,"dj":-2,"dayma":730.2068817204,"delta累计":264.0} +{"price":["730.04","730.06","730.08","730.1","730.12","730.14","730.16","730.18","730.2","730.22","730.24","730.26","730.28","730.3","730.32","730.34","730.36","730.38","730.4","730.42","730.44","730.46","730.48","730.5","730.52","730.54","730.56","730.58","730.6","730.62","730.64","730.66","730.68"],"Ask":[8,5,86,7,14,0,13,0,0,0,0,0,4,41,10,10,20,23,3,0,17,4,3,46,85,29,45,35,42,34,8,3,7],"Bid":[30,61,0,14,0,12,0,11,10,7,10,23,4,12,7,37,11,23,24,16,23,5,38,80,77,49,28,34,19,13,1,0,0],"symbol":"au2506","datetime":"2025-04-01 00:12:00","delta":-77.0,"close":730.06,"open":730.62,"high":730.68,"low":730.04,"volume":1382,"dj":-3,"dayma":730.2053191489,"delta累计":187.0} +{"price":["730.06","730.08","730.14","730.16","730.18","730.2","730.22","730.24","730.26","730.28","730.3","730.32","730.34","730.36","730.38","730.4","730.42","730.44","730.46","730.48","730.5","730.52","730.54","730.56","730.58"],"Ask":[4,3,16,17,11,31,7,12,15,18,21,44,3,115,22,75,67,30,9,0,16,18,26,25,5],"Bid":[8,6,0,19,57,10,11,10,18,54,31,22,17,28,45,59,77,13,0,26,20,23,13,0,0],"symbol":"au2506","datetime":"2025-04-01 00:15:00","delta":43.0,"close":730.38,"open":730.06,"high":730.58,"low":730.06,"volume":1307,"dj":0,"dayma":730.2071578947,"delta累计":230.0} +{"price":["730.14","730.16","730.18","730.2","730.22","730.24","730.26","730.28","730.3","730.32","730.34","730.36","730.38"],"Ask":[12,10,10,10,34,28,48,62,90,12,14,18,24],"Bid":[5,51,36,64,74,249,45,85,43,46,9,8,0],"symbol":"au2506","datetime":"2025-04-01 00:18:00","delta":-343.0,"close":730.16,"open":730.32,"high":730.38,"low":730.14,"volume":1140,"dj":0,"dayma":730.2066666667,"delta累计":-113.0} +{"price":["730.18","730.2","730.22","730.24","730.26","730.28","730.3","730.32","730.34","730.36","730.38","730.4","730.42","730.44","730.46","730.48","730.5","730.52"],"Ask":[4,4,16,16,32,15,15,43,32,47,11,18,68,36,43,59,20,24],"Bid":[0,0,0,13,0,17,28,31,16,19,5,25,37,45,42,29,4,0],"symbol":"au2506","datetime":"2025-04-01 00:21:00","delta":192.0,"close":730.44,"open":730.18,"high":730.52,"low":730.18,"volume":883,"dj":1,"dayma":730.2090721649,"delta累计":79.0} +{"price":["730.36","730.38","730.4","730.42","730.44","730.46","730.48","730.5","730.52","730.54","730.56","730.58","730.6","730.62","730.64","730.66"],"Ask":[0,13,22,26,26,30,58,19,27,21,46,45,48,59,44,7],"Bid":[11,13,24,32,18,30,28,4,14,18,23,46,38,47,18,0],"symbol":"au2506","datetime":"2025-04-01 00:24:00","delta":127.0,"close":730.58,"open":730.42,"high":730.66,"low":730.36,"volume":905,"dj":0,"dayma":730.2128571429,"delta累计":206.0} +{"price":["730.54","730.56","730.58","730.6","730.62","730.64","730.66","730.68","730.7","730.72","730.74","730.76","730.78","730.82","730.84","730.86","730.88","730.9","730.92","730.94"],"Ask":[4,0,16,12,20,25,13,6,8,12,34,31,25,0,28,48,38,36,5,10],"Bid":[0,6,26,6,28,26,9,7,5,30,41,23,14,25,32,31,17,37,0,0],"symbol":"au2506","datetime":"2025-04-01 00:27:00","delta":8.0,"close":730.9,"open":730.62,"high":730.94,"low":730.54,"volume":778,"dj":0,"dayma":730.2197979798,"delta累计":214.0} +{"price":["730.82","730.84","730.86","730.88","730.9","730.92","730.94","730.96","730.98","731.0","731.02","731.04","731.06"],"Ask":[0,22,39,76,32,49,30,24,35,31,86,28,8],"Bid":[11,24,87,24,92,44,40,41,63,29,10,2,0],"symbol":"au2506","datetime":"2025-04-01 00:30:00","delta":-7.0,"close":730.9,"open":730.92,"high":731.06,"low":730.82,"volume":979,"dj":0,"dayma":730.2266,"delta累计":207.0} +{"price":["730.8","730.82","730.84","730.86","730.88","730.9","730.92","730.94","730.96","730.98","731.0","731.02","731.04","731.06","731.08"],"Ask":[0,9,49,42,15,17,21,23,13,52,24,14,13,52,63],"Bid":[18,47,64,45,37,11,37,8,31,18,1,13,19,20,29],"symbol":"au2506","datetime":"2025-04-01 00:33:00","delta":9.0,"close":731.08,"open":730.88,"high":731.08,"low":730.8,"volume":835,"dj":0,"dayma":730.235049505,"delta累计":216.0} +{"price":["731.04","731.06","731.08","731.1","731.12","731.14","731.16","731.18","731.2","731.22","731.24","731.26","731.28","731.3","731.32","731.34","731.36","731.38","731.4","731.44"],"Ask":[23,33,13,18,64,21,10,25,62,28,14,27,34,45,87,60,62,58,28,36],"Bid":[32,19,12,3,10,25,18,26,66,5,24,41,52,26,36,45,25,25,0,0],"symbol":"au2506","datetime":"2025-04-01 00:36:00","delta":258.0,"close":731.36,"open":731.04,"high":731.44,"low":731.04,"volume":1341,"dj":0,"dayma":730.2460784314,"delta累计":474.0} +{"price":["731.16","731.18","731.2","731.22","731.24","731.26","731.28","731.3","731.32","731.34","731.36","731.38","731.4","731.42","731.44","731.46","731.48","731.5","731.52","731.54"],"Ask":[0,4,35,38,6,14,22,32,33,23,14,3,18,3,28,39,15,90,42,9],"Bid":[9,19,25,48,9,11,36,34,32,20,21,4,4,41,17,15,22,124,32,0],"symbol":"au2506","datetime":"2025-04-01 00:39:00","delta":-55.0,"close":731.52,"open":731.36,"high":731.54,"low":731.16,"volume":1040,"dj":0,"dayma":730.2584466019,"delta累计":419.0} +{"price":["731.3","731.32","731.34","731.36","731.38","731.4","731.42","731.44","731.46","731.48","731.5","731.52","731.54","731.56"],"Ask":[9,4,77,22,69,23,38,28,66,30,46,47,38,41],"Bid":[27,32,14,45,69,50,33,43,46,44,80,4,21,23],"symbol":"au2506","datetime":"2025-04-01 00:42:00","delta":7.0,"close":731.54,"open":731.5,"high":731.56,"low":731.3,"volume":1134,"dj":0,"dayma":730.2707692308,"delta累计":426.0} +{"price":["731.2","731.22","731.24","731.26","731.28","731.3","731.32","731.34","731.36","731.38","731.4","731.42","731.44","731.46","731.48","731.5","731.52","731.54","731.56","731.58","731.6","731.62"],"Ask":[0,4,7,34,11,45,35,8,16,45,17,18,38,11,10,2,3,0,3,15,55,27],"Bid":[7,68,44,10,17,42,7,6,34,29,19,12,40,22,14,3,3,10,11,30,33,2],"symbol":"au2506","datetime":"2025-04-01 00:45:00","delta":-59.0,"close":731.48,"open":731.58,"high":731.62,"low":731.2,"volume":953,"dj":0,"dayma":730.2822857143,"delta累计":367.0} +{"price":["731.48","731.5","731.52","731.54","731.56","731.58","731.6","731.62","731.64","731.66","731.68","731.7"],"Ask":[14,4,27,13,23,43,111,84,52,35,18,8],"Bid":[3,32,49,32,30,60,29,32,25,30,16,0],"symbol":"au2506","datetime":"2025-04-01 00:48:00","delta":94.0,"close":731.54,"open":731.48,"high":731.7,"low":731.48,"volume":837,"dj":0,"dayma":730.2941509434,"delta累计":461.0} +{"price":["731.52","731.54","731.56","731.58","731.6","731.62","731.64","731.66","731.68"],"Ask":[0,23,23,23,33,56,38,30,20],"Bid":[10,52,31,16,69,31,53,13,8],"symbol":"au2506","datetime":"2025-04-01 00:51:00","delta":-37.0,"close":731.56,"open":731.54,"high":731.68,"low":731.52,"volume":563,"dj":0,"dayma":730.3059813084,"delta累计":424.0} +{"price":["731.34","731.36","731.38","731.4","731.42","731.44","731.46","731.48","731.5","731.52","731.54","731.56","731.58","731.6","731.62","731.64","731.66"],"Ask":[0,5,4,17,22,25,6,0,4,4,4,35,13,48,11,11,31],"Bid":[17,9,16,58,11,8,19,50,12,9,7,50,37,40,21,21,22],"symbol":"au2506","datetime":"2025-04-01 00:54:00","delta":-167.0,"close":731.42,"open":731.56,"high":731.66,"low":731.34,"volume":684,"dj":0,"dayma":730.3162962963,"delta累计":257.0} +{"price":["731.16","731.18","731.2","731.22","731.24","731.26","731.28","731.3","731.32","731.34","731.36","731.38","731.4","731.42","731.44","731.46","731.48","731.5"],"Ask":[5,24,1,24,11,56,47,10,7,15,34,10,24,16,40,5,10,10],"Bid":[9,13,25,58,44,12,8,7,29,32,22,14,31,22,27,15,8,0],"symbol":"au2506","datetime":"2025-04-01 00:57:00","delta":-27.0,"close":731.3,"open":731.42,"high":731.5,"low":731.16,"volume":808,"dj":0,"dayma":730.3253211009,"delta累计":230.0} +{"price":["730.82","730.86","730.88","730.9","730.92","730.94","730.96","730.98","731.0","731.02","731.04","731.06","731.08","731.1","731.12","731.14","731.16","731.18","731.2","731.22","731.24","731.26","731.28","731.3","731.32","731.34"],"Ask":[0,0,0,6,19,50,93,18,21,42,6,4,18,32,29,9,8,2,13,5,6,9,9,0,3,2],"Bid":[4,4,13,38,91,53,20,21,74,22,9,4,22,29,20,5,8,15,17,10,18,13,0,12,2,0],"symbol":"au2506","datetime":"2025-04-01 01:00:00","delta":-120.0,"close":730.82,"open":731.32,"high":731.34,"low":730.82,"volume":1003,"dj":0,"dayma":730.3298181818,"delta累计":110.0} +{"price":["730.74","730.76","730.78","730.8","730.82","730.84","730.86","730.88","730.9","730.92","730.94","730.96","730.98","731.0","731.02","731.04","731.06","731.08","731.1","731.12","731.14","731.16","731.18","731.2","731.22"],"Ask":[0,14,20,2,40,17,36,5,5,16,46,52,26,20,2,38,37,31,71,30,20,11,5,6,8],"Bid":[23,10,0,35,18,0,23,0,8,18,11,20,68,6,33,31,46,39,8,8,5,8,26,5,0],"symbol":"au2506","datetime":"2025-04-01 01:03:00","delta":109.0,"close":731.16,"open":730.8,"high":731.22,"low":730.74,"volume":1099,"dj":0,"dayma":730.3372972973,"delta累计":219.0} +{"price":["731.08","731.1","731.12","731.14","731.16","731.18","731.2","731.22","731.24","731.26","731.28","731.3","731.32","731.34"],"Ask":[0,7,3,23,26,16,35,28,43,10,47,30,7,1],"Bid":[8,13,9,18,9,16,45,26,19,13,53,26,4,0],"symbol":"au2506","datetime":"2025-04-01 01:06:00","delta":17.0,"close":731.32,"open":731.16,"high":731.34,"low":731.08,"volume":559,"dj":0,"dayma":730.3460714286,"delta累计":236.0} +{"price":["731.14","731.16","731.18","731.2","731.22","731.24","731.26","731.28","731.3","731.32","731.34","731.36","731.38","731.4","731.42","731.44"],"Ask":[0,1,10,6,0,7,4,20,8,16,28,9,25,57,92,17],"Bid":[19,0,13,5,3,11,9,4,23,13,20,65,25,56,19,0],"symbol":"au2506","datetime":"2025-04-01 01:09:00","delta":15.0,"close":731.42,"open":731.3,"high":731.44,"low":731.14,"volume":628,"dj":0,"dayma":730.3555752212,"delta累计":251.0} +{"price":["731.38","731.4","731.42","731.44","731.46","731.48","731.5","731.52","731.54","731.56","731.58","731.6","731.62","731.64","731.66"],"Ask":[0,10,15,46,28,41,21,9,33,34,21,27,5,7,10],"Bid":[6,51,48,46,35,15,22,14,44,35,19,9,25,0,0],"symbol":"au2506","datetime":"2025-04-01 01:12:00","delta":-62.0,"close":731.62,"open":731.42,"high":731.66,"low":731.38,"volume":720,"dj":0,"dayma":730.3666666667,"delta累计":189.0} +{"price":["731.4","731.42","731.44","731.46","731.5","731.52","731.54","731.56","731.58","731.6"],"Ask":[0,14,3,15,17,13,49,33,52,11],"Bid":[7,20,26,14,24,31,39,53,31,0],"symbol":"au2506","datetime":"2025-04-01 01:15:00","delta":-38.0,"close":731.42,"open":731.58,"high":731.6,"low":731.4,"volume":481,"dj":0,"dayma":730.375826087,"delta累计":151.0} +{"price":["731.26","731.28","731.3","731.32","731.34","731.36","731.38","731.4","731.42","731.44","731.46","731.48","731.5","731.52"],"Ask":[0,34,1,28,1,20,45,32,14,4,25,1,8,2],"Bid":[6,41,20,7,18,54,64,12,6,6,7,6,7,0],"symbol":"au2506","datetime":"2025-04-01 01:18:00","delta":-39.0,"close":731.36,"open":731.44,"high":731.52,"low":731.26,"volume":498,"dj":0,"dayma":730.3843103448,"delta累计":112.0} +{"price":["731.32","731.34","731.36","731.38","731.4","731.42","731.44","731.46","731.48","731.5","731.52","731.54","731.56","731.58"],"Ask":[1,1,9,1,24,3,13,8,35,6,13,25,7,40],"Bid":[7,5,13,5,24,8,10,23,39,1,10,21,35,2],"symbol":"au2506","datetime":"2025-04-01 01:21:00","delta":-17.0,"close":731.44,"open":731.36,"high":731.58,"low":731.32,"volume":422,"dj":0,"dayma":730.3933333333,"delta累计":95.0} +{"price":["731.1","731.12","731.14","731.16","731.18","731.2","731.22","731.24","731.26","731.28","731.3","731.32","731.34","731.36","731.38","731.42","731.44","731.46"],"Ask":[20,7,10,4,10,36,43,31,63,40,0,3,16,41,11,0,6,5],"Bid":[2,19,14,48,16,41,41,45,48,16,6,13,10,28,0,22,0,0],"symbol":"au2506","datetime":"2025-04-01 01:24:00","delta":-23.0,"close":731.1,"open":731.44,"high":731.46,"low":731.1,"volume":778,"dj":0,"dayma":730.3993220339,"delta累计":72.0} +{"price":["730.86","730.88","730.9","730.92","730.94","730.96","730.98","731.0","731.02","731.04","731.06","731.08","731.1","731.12","731.14","731.16","731.2","731.22","731.24","731.26"],"Ask":[0,20,15,44,63,63,30,9,9,0,11,24,45,48,32,13,16,13,6,6],"Bid":[19,18,40,66,56,15,14,36,7,5,17,39,45,10,10,0,0,45,0,0],"symbol":"au2506","datetime":"2025-04-01 01:27:00","delta":25.0,"close":731.26,"open":731.1,"high":731.26,"low":730.86,"volume":960,"dj":0,"dayma":730.4065546218,"delta累计":97.0} +{"price":["731.0","731.02","731.04","731.06","731.08","731.1","731.12","731.14","731.16","731.18","731.2","731.22","731.24","731.26","731.28","731.3","731.32","731.34"],"Ask":[1,14,9,14,12,50,34,6,10,13,4,24,36,13,36,35,34,7],"Bid":[17,10,21,12,32,8,6,15,28,14,9,28,25,15,25,9,2,0],"symbol":"au2506","datetime":"2025-04-01 01:30:00","delta":76.0,"close":731.08,"open":731.26,"high":731.34,"low":731.0,"volume":681,"dj":0,"dayma":730.4121666667,"delta累计":173.0} +{"price":["730.82","730.84","730.86","730.88","730.9","730.92","730.94","730.96","730.98","731.0","731.02","731.04","731.06","731.08"],"Ask":[0,6,22,39,11,18,37,24,35,29,5,17,2,4],"Bid":[8,18,12,31,42,30,22,25,32,6,24,29,16,0],"symbol":"au2506","datetime":"2025-04-01 01:33:00","delta":-46.0,"close":730.92,"open":731.06,"high":731.08,"low":730.82,"volume":576,"dj":0,"dayma":730.4163636364,"delta累计":127.0} +{"price":["730.76","730.78","730.8","730.82","730.84","730.86","730.88","730.9","730.92","730.94"],"Ask":[27,13,0,20,6,8,14,34,32,4],"Bid":[13,34,54,16,11,24,14,16,22,1],"symbol":"au2506","datetime":"2025-04-01 01:36:00","delta":-47.0,"close":730.82,"open":730.92,"high":730.94,"low":730.76,"volume":401,"dj":0,"dayma":730.4196721311,"delta累计":80.0} +{"price":["730.8","730.82","730.84","730.86","730.88","730.9","730.92","730.94","730.96","730.98","731.0","731.02","731.04","731.06","731.08","731.1","731.12","731.14"],"Ask":[0,2,17,5,10,24,36,32,1,23,40,19,28,15,2,29,5,14],"Bid":[5,8,2,2,7,9,12,3,10,22,9,21,33,11,25,29,10,0],"symbol":"au2506","datetime":"2025-04-01 01:39:00","delta":84.0,"close":731.04,"open":730.82,"high":731.14,"low":730.8,"volume":549,"dj":1,"dayma":730.4247154472,"delta累计":164.0} +{"price":["730.92","730.94","730.96","730.98","731.0","731.02","731.04","731.06","731.08","731.1","731.12","731.14","731.16"],"Ask":[0,0,11,2,11,15,3,32,10,44,8,16,7],"Bid":[20,9,14,14,15,5,16,52,23,7,11,12,0],"symbol":"au2506","datetime":"2025-04-01 01:42:00","delta":-39.0,"close":731.1,"open":731.04,"high":731.16,"low":730.92,"volume":381,"dj":0,"dayma":730.4301612903,"delta累计":125.0} +{"price":["730.94","730.96","730.98","731.0","731.02","731.04","731.06","731.08","731.1","731.12"],"Ask":[0,2,24,11,11,9,4,12,19,3],"Bid":[24,3,3,20,24,9,21,31,15,0],"symbol":"au2506","datetime":"2025-04-01 01:45:00","delta":-55.0,"close":731.0,"open":731.1,"high":731.12,"low":730.94,"volume":261,"dj":0,"dayma":730.43472,"delta累计":70.0} +{"price":["730.9","730.92","730.94","730.96","730.98","731.0","731.02","731.04"],"Ask":[0,4,12,15,11,19,15,1],"Bid":[11,9,10,33,7,26,3,0],"symbol":"au2506","datetime":"2025-04-01 01:48:00","delta":-22.0,"close":730.94,"open":731.0,"high":731.04,"low":730.9,"volume":213,"dj":0,"dayma":730.4387301587,"delta累计":48.0} +{"price":["730.88","730.9","730.92","730.94","730.96","730.98","731.0","731.02","731.04","731.06","731.08","731.1","731.12","731.14","731.16","731.18"],"Ask":[0,0,25,20,2,6,13,1,16,14,3,15,8,22,20,12],"Bid":[2,15,0,4,1,7,23,2,8,13,20,14,15,15,24,0],"symbol":"au2506","datetime":"2025-04-01 01:51:00","delta":14.0,"close":731.04,"open":730.9,"high":731.18,"low":730.88,"volume":371,"dj":0,"dayma":730.4434645669,"delta累计":62.0} +{"price":["730.98","731.0","731.02","731.04","731.06","731.14","731.16","731.18","731.2","731.22"],"Ask":[0,18,9,16,3,12,28,49,37,3],"Bid":[2,71,1,1,3,16,25,26,0,0],"symbol":"au2506","datetime":"2025-04-01 01:54:00","delta":30.0,"close":731.18,"open":731.04,"high":731.22,"low":730.98,"volume":332,"dj":0,"dayma":730.44921875,"delta累计":92.0} +{"price":["731.16","731.18","731.2","731.22","731.24","731.26","731.28","731.3"],"Ask":[0,7,19,10,25,64,23,11],"Bid":[4,13,10,48,36,39,0,0],"symbol":"au2506","datetime":"2025-04-01 01:57:00","delta":9.0,"close":731.2,"open":731.18,"high":731.3,"low":731.16,"volume":330,"dj":0,"dayma":730.4550387597,"delta累计":101.0} +{"price":["731.14","731.16","731.18","731.2","731.22","731.24"],"Ask":[0,16,25,33,22,13],"Bid":[28,46,30,4,10,0],"symbol":"au2506","datetime":"2025-04-01 02:00:00","delta":-9.0,"close":731.16,"open":731.2,"high":731.24,"low":731.14,"volume":236,"dj":0,"dayma":730.4604615385,"delta累计":92.0} +{"price":["730.98","731.0","731.02","731.04","731.06","731.08","731.1","731.12","731.14","731.16"],"Ask":[1,16,64,46,23,15,3,17,19,6],"Bid":[33,69,28,20,5,18,22,22,1,0],"symbol":"au2506","datetime":"2025-04-01 02:03:00","delta":-8.0,"close":731.16,"open":731.1,"high":731.16,"low":730.98,"volume":459,"dj":0,"dayma":730.4658015267,"delta累计":84.0} +{"price":["731.14","731.16","731.18","731.2","731.22","731.24","731.26","731.28","731.3","731.32","731.34","731.36"],"Ask":[0,12,7,8,15,10,19,37,22,15,10,10],"Bid":[3,5,0,10,35,34,18,15,7,10,10,0],"symbol":"au2506","datetime":"2025-04-01 02:06:00","delta":18.0,"close":731.26,"open":731.14,"high":731.36,"low":731.14,"volume":351,"dj":0,"dayma":730.4718181818,"delta累计":102.0} +{"price":["731.2","731.22","731.24","731.26","731.28","731.3","731.32","731.34","731.36"],"Ask":[0,7,1,17,36,58,9,16,6],"Bid":[19,9,4,23,23,18,5,7,0],"symbol":"au2506","datetime":"2025-04-01 02:09:00","delta":42.0,"close":731.36,"open":731.22,"high":731.36,"low":731.2,"volume":271,"dj":0,"dayma":730.4784962406,"delta累计":144.0} +{"price":["731.32","731.34","731.36","731.38","731.4","731.46","731.48","731.5","731.52","731.54","731.56","731.58","731.6","731.62"],"Ask":[0,0,8,8,20,8,11,31,83,26,19,48,14,28],"Bid":[2,9,2,24,1,0,34,62,34,34,9,20,10,0],"symbol":"au2506","datetime":"2025-04-01 02:12:00","delta":63.0,"close":731.58,"open":731.36,"high":731.62,"low":731.32,"volume":614,"dj":0,"dayma":730.4867164179,"delta累计":207.0} +{"price":["731.52","731.56","731.58","731.6","731.62","731.64","731.66","731.68","731.7"],"Ask":[0,4,10,18,26,17,37,19,23],"Bid":[15,5,13,47,18,32,19,10,0],"symbol":"au2506","datetime":"2025-04-01 02:15:00","delta":-5.0,"close":731.58,"open":731.58,"high":731.7,"low":731.52,"volume":346,"dj":0,"dayma":730.4948148148,"delta累计":202.0} +{"price":["731.44","731.46","731.48","731.5","731.52","731.54","731.56","731.58","731.6","731.62","731.64"],"Ask":[2,18,8,24,6,12,5,6,8,11,10],"Bid":[7,27,1,31,9,20,13,10,11,5,0],"symbol":"au2506","datetime":"2025-04-01 02:18:00","delta":-24.0,"close":731.58,"open":731.58,"high":731.64,"low":731.44,"volume":294,"dj":0,"dayma":730.5027941176,"delta累计":178.0} +{"price":["731.6","731.62","731.64","731.66","731.68","731.7","731.72","731.74","731.76","731.78","731.8","731.82","731.84","731.86","731.88","731.9","731.92"],"Ask":[0,5,12,20,34,10,8,8,26,104,36,6,14,8,21,8,10],"Bid":[3,9,18,8,0,0,3,30,16,33,3,10,0,0,17,9,0],"symbol":"au2506","datetime":"2025-04-01 02:21:00","delta":171.0,"close":731.88,"open":731.62,"high":731.92,"low":731.6,"volume":509,"dj":1,"dayma":730.5128467153,"delta累计":349.0} +{"price":["731.86","731.88","731.9","731.92","731.94","731.96","731.98","732.0","732.02","732.04","732.06","732.08","732.1","732.12","732.14","732.16","732.18","732.2"],"Ask":[7,6,32,23,35,23,23,93,8,12,4,9,16,27,21,29,9,13],"Bid":[15,0,14,25,21,0,4,0,4,2,8,0,13,20,25,5,0,0],"symbol":"au2506","datetime":"2025-04-01 02:24:00","delta":234.0,"close":732.2,"open":731.86,"high":732.2,"low":731.86,"volume":566,"dj":1,"dayma":730.5250724638,"delta累计":583.0} +{"price":["732.04","732.06","732.08","732.1","732.14","732.16","732.18","732.2","732.22","732.24","732.26","732.28","732.3"],"Ask":[0,6,6,16,0,2,12,18,39,60,51,15,21],"Bid":[17,27,1,6,10,14,47,47,55,127,32,18,0],"symbol":"au2506","datetime":"2025-04-01 02:27:00","delta":-155.0,"close":732.1,"open":732.22,"high":732.3,"low":732.04,"volume":693,"dj":0,"dayma":730.5364028777,"delta累计":428.0} +{"price":["735.96","735.98","736.0","736.02","736.04","736.06","736.08","736.1","736.12","736.14","736.16","736.18"],"Ask":[0,13,32,6,4,0,18,15,0,25,0,24],"Bid":[9,26,53,28,0,35,4,76,6,29,16,0],"symbol":"au2506","datetime":"2025-04-01 09:45:00","delta":-145.0,"close":736.08,"open":736.14,"high":736.18,"low":735.96,"volume":472,"dj":0,"dayma":731.2615686275,"delta累计":222.0} +{"price":["736.0","736.02","736.04","736.06","736.08","736.1","736.12","736.14","736.16","736.18","736.2","736.22","736.24","736.26","736.28","736.3","736.32","736.34","736.36","736.38","736.4","736.42","736.44","736.46","736.48","736.5","736.52","736.54","736.56"],"Ask":[7,7,0,9,39,50,124,165,142,74,98,58,27,54,40,54,113,12,70,53,107,26,20,30,7,82,21,161,35],"Bid":[38,7,10,132,168,112,139,234,43,90,93,34,71,24,16,0,0,18,24,53,47,0,0,31,22,96,13,59,0],"symbol":"au2506","datetime":"2025-04-01 09:48:00","delta":111.0,"close":736.5,"open":736.1,"high":736.58,"low":736.0,"volume":3568,"dj":2,"dayma":731.3623076923,"delta累计":333.0} +{"price":["736.16","736.18","736.2","736.22","736.24","736.26","736.28","736.3","736.32","736.34","736.36","736.38","736.4","736.42","736.44","736.46","736.48","736.5","736.52"],"Ask":[11,98,37,97,152,110,61,13,18,52,20,78,52,101,29,24,70,59,8],"Bid":[63,145,75,69,98,59,28,45,44,44,117,76,57,61,58,68,47,17,0],"symbol":"au2506","datetime":"2025-04-01 09:51:00","delta":-81.0,"close":736.2,"open":736.48,"high":736.52,"low":736.16,"volume":2373,"dj":0,"dayma":731.4535849057,"delta累计":252.0} +{"price":["736.18","736.2","736.22","736.24","736.26","736.28","736.3","736.32","736.34","736.36","736.38","736.4","736.42","736.44","736.46","736.48","736.5","736.52","736.54"],"Ask":[0,7,7,23,0,7,21,15,85,114,168,50,30,0,137,72,303,47,20],"Bid":[21,0,0,0,27,18,48,69,72,117,108,22,9,26,168,129,25,24,0],"symbol":"au2506","datetime":"2025-04-01 09:54:00","delta":223.0,"close":736.28,"open":736.18,"high":736.54,"low":736.18,"volume":2106,"dj":0,"dayma":731.542962963,"delta累计":475.0} +{"price":["735.68","735.7","735.72","735.74","735.76","735.78","735.8","735.82","735.84","735.86","735.88","735.9","735.92","735.94","735.96","735.98","736.0","736.02","736.04","736.06","736.08","736.1","736.12","736.14","736.16","736.18","736.2","736.22","736.24","736.26","736.28"],"Ask":[0,0,62,17,21,49,187,73,29,61,10,8,12,5,31,59,205,80,0,0,5,0,33,46,65,78,145,72,25,5,11],"Bid":[8,13,65,36,0,59,93,44,0,21,38,10,4,40,137,70,99,34,19,4,44,67,32,90,117,117,123,49,22,6,0],"symbol":"au2506","datetime":"2025-04-01 09:57:00","delta":-67.0,"close":735.88,"open":736.26,"high":736.28,"low":735.68,"volume":3111,"dj":0,"dayma":731.6218181818,"delta累计":408.0} +{"price":["735.8","735.82","735.84","735.86","735.88","735.9","735.92","735.94","735.96","735.98","736.0","736.02","736.04","736.06","736.08","736.1","736.12","736.14","736.16"],"Ask":[0,0,6,60,87,70,57,116,113,78,59,92,34,57,50,36,2,51,22],"Bid":[29,28,30,38,25,47,56,102,25,120,107,31,39,55,11,11,6,19,0],"symbol":"au2506","datetime":"2025-04-01 10:00:00","delta":211.0,"close":736.0,"open":735.88,"high":736.16,"low":735.8,"volume":1868,"dj":0,"dayma":731.7,"delta累计":619.0} +{"price":["735.54","735.56","735.58","735.6","735.62","735.64","735.66","735.68","735.7","735.72","735.74","735.76","735.78","735.8","735.82","735.84","735.86","735.88","735.9","735.92","735.94","735.98","736.0"],"Ask":[68,37,39,71,29,72,30,28,34,36,79,7,34,44,43,45,60,99,17,0,19,5,4],"Bid":[78,15,46,51,17,15,59,75,132,22,31,46,42,70,33,47,49,6,39,14,49,54,0],"symbol":"au2506","datetime":"2025-04-01 10:03:00","delta":-90.0,"close":735.88,"open":735.98,"high":736.0,"low":735.54,"volume":2228,"dj":0,"dayma":731.7733333333,"delta累计":529.0} +{"price":["735.56","735.58","735.6","735.62","735.64","735.66","735.68","735.7","735.72","735.74","735.76","735.78","735.8","735.82","735.84","735.86","735.88","735.9","735.92","735.94","735.96","735.98","736.0","736.02","736.04","736.06","736.08","736.1","736.12","736.14","736.16","736.18"],"Ask":[0,0,7,33,86,84,109,53,133,58,26,29,17,3,26,0,18,24,0,11,10,21,50,13,9,23,21,35,0,39,78,22],"Bid":[28,33,40,53,86,43,84,94,43,31,36,51,0,14,18,7,0,10,21,45,24,30,57,8,13,0,0,40,12,93,47,0],"symbol":"au2506","datetime":"2025-04-01 10:06:00","delta":-23.0,"close":735.74,"open":735.86,"high":736.18,"low":735.56,"volume":2277,"dj":0,"dayma":731.8417241379,"delta累计":506.0} +{"price":["735.68","735.7","735.72","735.74","735.76","735.78","735.8","735.82","735.84","735.86","735.88","735.9","735.92","735.94","735.96","735.98","736.0","736.02","736.04","736.06","736.08","736.1","736.12","736.14","736.16","736.18","736.2","736.22","736.24","736.26","736.28","736.3"],"Ask":[0,16,22,29,20,60,16,18,0,8,0,31,16,17,27,8,63,8,0,17,37,78,169,50,57,51,27,43,64,49,57,7],"Bid":[1,26,8,27,33,21,7,4,3,0,4,7,0,4,27,32,13,5,11,45,60,91,64,70,43,33,27,104,87,96,23,0],"symbol":"au2506","datetime":"2025-04-01 10:09:00","delta":89.0,"close":736.18,"open":735.8,"high":736.3,"low":735.68,"volume":2150,"dj":0,"dayma":731.9152542373,"delta累计":595.0} +{"price":["736.16","736.18","736.22","736.24","736.26","736.3","736.32","736.34","736.36","736.38","736.4","736.42","736.44","736.46","736.48","736.5","736.52","736.54","736.56","736.58","736.6","736.62","736.64","736.66","736.68","736.7","736.72","736.74","736.76","736.78","736.8","736.82","736.84","736.86","736.9"],"Ask":[0,1,9,3,12,28,15,58,52,103,59,33,54,39,77,157,55,23,85,0,64,33,17,16,9,136,64,0,23,28,78,43,3,20,24],"Bid":[13,7,11,2,0,13,81,50,59,83,62,42,58,63,83,74,37,14,60,13,56,27,62,9,110,34,61,17,18,37,13,9,45,21,0],"symbol":"au2506","datetime":"2025-04-01 10:12:00","delta":77.0,"close":736.9,"open":736.18,"high":736.9,"low":736.16,"volume":2935,"dj":0,"dayma":731.9983333333,"delta累计":672.0} +{"price":["736.82","736.84","736.86","736.88","736.9","736.92","736.94","736.96","736.98","737.0","737.02","737.04","737.06","737.08","737.1","737.12"],"Ask":[0,0,18,64,217,344,129,125,136,387,63,55,18,5,143,9],"Bid":[19,38,82,202,321,258,29,100,44,163,47,35,43,18,123,0],"symbol":"au2506","datetime":"2025-04-01 10:15:00","delta":191.0,"close":736.9,"open":736.92,"high":737.12,"low":736.82,"volume":3540,"dj":0,"dayma":732.0786885246,"delta累计":863.0} +{"price":["737.28"],"Ask":[145],"Bid":[0],"symbol":"au2506","datetime":"2025-04-01 10:30:00","delta":145.0,"close":737.28,"open":737.28,"high":737.28,"low":737.28,"volume":145,"dj":0,"dayma":732.1625806452,"delta累计":1008.0} +{"price":["737.3","737.32","737.36","737.4","737.42","737.46","737.48","737.5","737.52","737.54","737.56","737.58","737.6","737.62","737.64","737.66","737.68","737.7","737.72","737.74","737.76","737.78","737.8","737.82","737.84","737.86","737.88","737.9"],"Ask":[102,0,0,46,74,0,0,87,123,20,15,92,101,87,115,116,92,224,65,160,192,77,163,113,162,72,42,101],"Bid":[0,61,63,66,0,8,37,85,28,7,108,191,140,137,70,248,193,210,119,33,178,111,133,235,0,23,0,0],"symbol":"au2506","datetime":"2025-04-01 10:33:00","delta":-43.0,"close":737.8,"open":737.3,"high":737.9,"low":737.3,"volume":5379,"dj":0,"dayma":732.2520634921,"delta累计":965.0} +{"price":["737.54","737.56","737.58","737.6","737.62","737.64","737.66","737.68","737.7","737.72","737.74","737.76","737.78","737.8","737.82"],"Ask":[10,17,24,23,65,54,30,16,71,22,106,109,90,125,21],"Bid":[34,50,57,132,87,45,48,67,119,59,221,102,58,78,8],"symbol":"au2506","datetime":"2025-04-01 10:36:00","delta":-382.0,"close":737.62,"open":737.8,"high":737.82,"low":737.54,"volume":2077,"dj":0,"dayma":732.3359375,"delta累计":583.0} +{"price":["737.36","737.38","737.4","737.42","737.44","737.46","737.48","737.5","737.52","737.54","737.56","737.58","737.6","737.62","737.64","737.66"],"Ask":[0,35,42,90,61,100,39,104,91,36,77,40,47,23,17,1],"Bid":[19,46,78,94,8,44,77,132,197,45,58,34,14,4,0,0],"symbol":"au2506","datetime":"2025-04-01 10:39:00","delta":-47.0,"close":737.4,"open":737.64,"high":737.66,"low":737.36,"volume":1743,"dj":0,"dayma":732.4138461538,"delta累计":536.0} +{"price":["737.16","737.18","737.2","737.22","737.24","737.26","737.28","737.3","737.32","737.34","737.36","737.38","737.4","737.42","737.44","737.46","737.48","737.5","737.52","737.54","737.56","737.58","737.6","737.62"],"Ask":[0,38,22,28,0,21,14,19,26,40,47,50,97,51,82,68,13,62,15,48,44,104,38,25],"Bid":[27,1,22,0,15,0,17,37,27,70,30,70,108,49,27,40,24,31,8,72,27,22,0,0],"symbol":"au2506","datetime":"2025-04-01 10:42:00","delta":228.0,"close":737.38,"open":737.38,"high":737.62,"low":737.16,"volume":1793,"dj":0,"dayma":732.4890909091,"delta累计":764.0} +{"price":["737.3","737.32","737.34","737.36","737.38","737.4","737.42","737.44","737.46","737.48","737.5","737.52","737.54","737.56","737.58","737.6","737.62","737.66","737.68","737.7","737.72","737.74"],"Ask":[13,108,5,81,15,12,1,38,49,39,83,24,16,25,20,29,3,24,34,61,103,54],"Bid":[28,66,18,10,0,23,20,25,31,29,24,0,0,2,11,0,18,31,106,50,8,0],"symbol":"au2506","datetime":"2025-04-01 10:45:00","delta":337.0,"close":737.74,"open":737.38,"high":737.74,"low":737.3,"volume":1425,"dj":1,"dayma":732.5674626866,"delta累计":1101.0} +{"price":["737.66","737.68","737.7","737.72","737.74","737.76","737.78","737.8","737.82","737.84","737.86","737.88","737.9","737.92","737.94","737.96","737.98","738.0","738.02","738.04","738.06","738.08","738.1","738.12","738.14","738.16","738.18","738.2","738.22","738.24"],"Ask":[0,6,92,63,151,117,50,58,40,102,28,41,3,14,18,5,9,3,93,13,58,16,40,9,51,94,22,99,0,13],"Bid":[18,11,62,84,112,44,19,52,140,51,20,0,14,49,0,21,109,25,0,14,0,23,63,18,98,75,74,62,18,0],"symbol":"au2506","datetime":"2025-04-01 10:48:00","delta":32.0,"close":738.0,"open":737.74,"high":738.24,"low":737.66,"volume":2707,"dj":2,"dayma":732.6473529412,"delta累计":1133.0} +{"price":["737.86","737.88","737.9","737.92","737.94","737.96","737.98","738.0","738.02","738.04","738.06","738.08","738.1","738.12","738.14","738.16","738.18","738.2"],"Ask":[0,51,82,17,28,55,58,63,67,96,33,49,56,10,25,73,111,21],"Bid":[14,37,49,38,47,44,36,38,54,106,73,56,27,41,64,180,11,0],"symbol":"au2506","datetime":"2025-04-01 10:51:00","delta":-20.0,"close":738.1,"open":738.04,"high":738.2,"low":737.86,"volume":2003,"dj":0,"dayma":732.7263768116,"delta累计":1113.0} +{"price":["738.0","738.02","738.04","738.06","738.08","738.1","738.12","738.14","738.16","738.18","738.2","738.22","738.24","738.26","738.28","738.3","738.32"],"Ask":[0,2,31,50,50,61,19,149,52,62,77,37,49,62,55,70,59],"Bid":[7,26,37,38,25,62,22,18,51,46,70,64,18,119,20,0,0],"symbol":"au2506","datetime":"2025-04-01 10:54:00","delta":262.0,"close":738.28,"open":738.08,"high":738.34,"low":738.0,"volume":1640,"dj":0,"dayma":732.8057142857,"delta累计":1375.0} +{"price":["738.18","738.2","738.22","738.24","738.26","738.28","738.3","738.32","738.34","738.36","738.38","738.4","738.42","738.44","738.46"],"Ask":[8,61,73,66,47,63,82,67,14,62,149,88,81,22,18],"Bid":[28,95,66,11,57,15,168,43,80,75,80,43,16,0,1],"symbol":"au2506","datetime":"2025-04-01 10:57:00","delta":123.0,"close":738.42,"open":738.26,"high":738.46,"low":738.18,"volume":1826,"dj":0,"dayma":732.8847887324,"delta累计":1498.0} +{"price":["738.2","738.22","738.24","738.26","738.28","738.3","738.32","738.34","738.36","738.38","738.4","738.42","738.44","738.46","738.48","738.5","738.52","738.54","738.56","738.58","738.6","738.62"],"Ask":[17,15,29,45,46,27,75,38,13,24,27,58,132,129,82,134,24,15,46,73,43,32],"Bid":[49,27,16,16,53,37,104,18,54,53,32,99,82,93,29,54,45,118,27,33,17,0],"symbol":"au2506","datetime":"2025-04-01 11:00:00","delta":68.0,"close":738.34,"open":738.46,"high":738.62,"low":738.2,"volume":2335,"dj":0,"dayma":732.9605555556,"delta累计":1566.0} +{"price":["738.1","738.12","738.14","738.16","738.18","738.2","738.22","738.24","738.26","738.28","738.3","738.32","738.34","738.36"],"Ask":[31,164,40,77,53,36,70,41,71,63,39,41,16,28],"Bid":[100,80,16,72,71,40,45,36,76,68,5,24,0,0],"symbol":"au2506","datetime":"2025-04-01 11:03:00","delta":137.0,"close":738.36,"open":738.32,"high":738.36,"low":738.1,"volume":1614,"dj":0,"dayma":733.0345205479,"delta累计":1703.0} +{"price":["738.08","738.12","738.14","738.16","738.18","738.2","738.22","738.24","738.26","738.28","738.3","738.32","738.34","738.36","738.38","738.4","738.42","738.44","738.46","738.48"],"Ask":[0,0,0,11,29,6,3,39,24,12,52,29,46,49,89,69,20,48,13,20],"Bid":[15,6,13,18,31,38,50,36,33,29,76,62,60,34,90,104,18,16,4,18],"symbol":"au2506","datetime":"2025-04-01 11:06:00","delta":-192.0,"close":738.36,"open":738.34,"high":738.48,"low":738.08,"volume":1399,"dj":0,"dayma":733.1064864865,"delta累计":1511.0} +{"price":["738.0","738.02","738.04","738.06","738.08","738.1","738.12","738.14","738.16","738.18","738.2","738.22","738.24","738.26","738.28","738.3","738.32","738.34","738.36","738.38","738.4","738.46"],"Ask":[0,2,64,77,151,138,95,61,26,56,47,21,185,5,14,0,2,29,5,10,0,31],"Bid":[54,25,42,43,40,114,32,34,43,36,62,42,87,0,0,24,0,6,9,43,9,0],"symbol":"au2506","datetime":"2025-04-01 11:09:00","delta":274.0,"close":738.16,"open":738.36,"high":738.46,"low":738.0,"volume":1971,"dj":0,"dayma":733.1738666667,"delta累计":1785.0} +{"price":["737.74","737.78","737.8","737.82","737.84","737.86","737.88","737.9","737.92","737.94","737.96","737.98","738.0","738.02","738.04","738.06","738.08","738.1","738.12","738.14","738.16","738.18"],"Ask":[0,1,8,14,51,65,28,41,44,58,2,52,41,126,19,46,37,46,41,61,24,3],"Bid":[10,28,49,33,54,43,15,106,48,23,25,16,38,16,46,36,59,12,48,44,6,0],"symbol":"au2506","datetime":"2025-04-01 11:12:00","delta":53.0,"close":737.78,"open":738.14,"high":738.18,"low":737.74,"volume":1684,"dj":-1,"dayma":733.2344736842,"delta累计":1838.0} +{"price":["737.78","737.8","737.82","737.84","737.86","737.88","737.9","737.94","737.96","738.02","738.04","738.06","738.08","738.1","738.12","738.14","738.16","738.18","738.2","738.22"],"Ask":[13,58,13,96,21,86,32,59,25,4,0,21,30,66,177,34,50,77,52,26],"Bid":[23,5,25,37,12,62,0,0,0,0,9,52,79,82,99,79,45,1,19,0],"symbol":"au2506","datetime":"2025-04-01 11:15:00","delta":311.0,"close":738.12,"open":737.78,"high":738.22,"low":737.78,"volume":1719,"dj":1,"dayma":733.2979220779,"delta累计":2149.0} +{"price":["738.06","738.1","738.12","738.14","738.16","738.18","738.2","738.22","738.24","738.26","738.28","738.3","738.32","738.34","738.36","738.38","738.4"],"Ask":[0,7,19,16,17,18,39,41,12,39,25,79,86,60,59,43,2],"Bid":[3,4,16,23,7,13,53,17,8,32,27,59,33,67,40,0,0],"symbol":"au2506","datetime":"2025-04-01 11:18:00","delta":160.0,"close":738.36,"open":738.14,"high":738.4,"low":738.06,"volume":1034,"dj":0,"dayma":733.3628205128,"delta累计":2309.0} +{"price":["738.08","738.1","738.12","738.14","738.16","738.18","738.2","738.22","738.24","738.26","738.28","738.3","738.32","738.34","738.36","738.38","738.4","738.42","738.44","738.46","738.48","738.5"],"Ask":[0,16,30,4,24,5,18,2,27,1,6,11,19,5,28,35,58,41,68,45,91,12],"Bid":[2,52,17,16,17,17,20,6,1,18,39,52,29,35,21,71,78,81,103,20,28,0],"symbol":"au2506","datetime":"2025-04-01 11:21:00","delta":-177.0,"close":738.1,"open":738.36,"high":738.5,"low":738.08,"volume":1327,"dj":0,"dayma":733.4227848101,"delta累计":2132.0} +{"price":["737.92","737.94","737.96","737.98","738.0","738.02","738.04","738.06","738.08","738.1","738.12","738.14","738.16","738.18","738.2","738.22","738.24"],"Ask":[0,18,45,107,106,20,22,37,9,23,67,63,58,50,10,4,5],"Bid":[11,85,56,86,36,0,14,22,19,29,40,33,50,13,6,0,0],"symbol":"au2506","datetime":"2025-04-01 11:24:00","delta":144.0,"close":738.2,"open":738.08,"high":738.24,"low":737.92,"volume":1292,"dj":0,"dayma":733.4825,"delta累计":2276.0} +{"price":["738.1","738.12","738.14","738.16","738.18","738.2","738.22","738.24","738.26"],"Ask":[0,2,3,44,103,102,66,19,29],"Bid":[13,22,33,103,56,34,34,13,5],"symbol":"au2506","datetime":"2025-04-01 11:27:00","delta":55.0,"close":738.2,"open":738.2,"high":738.26,"low":738.1,"volume":751,"dj":0,"dayma":733.5407407407,"delta累计":2331.0} +{"price":["738.16","738.18","738.2","738.22","738.24","738.26","738.28","738.3","738.32","738.34","738.36","738.38","738.4","738.42","738.44","738.46","738.48"],"Ask":[0,0,14,40,63,67,17,29,11,9,11,29,75,51,40,107,20],"Bid":[2,41,47,28,35,17,6,6,48,22,96,65,52,48,67,23,0],"symbol":"au2506","datetime":"2025-04-01 11:30:00","delta":-20.0,"close":738.46,"open":738.2,"high":738.48,"low":738.16,"volume":1264,"dj":0,"dayma":733.6007317073,"delta累计":2311.0} +{"price":["738.5"],"Ask":[227],"Bid":[0],"symbol":"au2506","datetime":"2025-04-01 13:30:00","delta":227.0,"close":738.5,"open":738.5,"high":738.5,"low":738.5,"volume":227,"dj":0,"dayma":733.6597590361,"delta累计":2538.0} +{"price":["738.76","738.78","738.8","738.82","738.84","738.86","738.88","738.9","738.92","738.94","738.96","738.98","739.0","739.02","739.04","739.06","739.08","739.1","739.12","739.14","739.16","739.18","739.22","739.24","739.26","739.28"],"Ask":[90,232,68,59,60,22,95,312,212,68,96,154,63,93,65,0,49,0,41,17,9,228,27,49,118,61],"Bid":[28,17,3,54,16,57,102,106,131,49,97,315,24,26,0,15,31,18,58,6,67,5,24,82,95,7],"symbol":"au2506","datetime":"2025-04-01 13:33:00","delta":855.0,"close":739.26,"open":738.66,"high":739.28,"low":738.66,"volume":4367,"dj":1,"dayma":733.7264285714,"delta累计":3393.0} +{"price":["739.18","739.2","739.22","739.24","739.26","739.28","739.3","739.32","739.34","739.36","739.38","739.4","739.42","739.44","739.46"],"Ask":[0,29,0,46,39,132,232,162,149,61,80,108,49,46,40],"Bid":[4,53,24,44,92,151,240,57,84,46,100,23,43,15,25],"symbol":"au2506","datetime":"2025-04-01 13:36:00","delta":172.0,"close":739.34,"open":739.28,"high":739.46,"low":739.18,"volume":2361,"dj":0,"dayma":733.7924705882,"delta累计":3565.0} +{"price":["739.26","739.28","739.3","739.32","739.34","739.36","739.38","739.4","739.42","739.46","739.48","739.5","739.52","739.54","739.56","739.58","739.6","739.62","739.64","739.66","739.68","739.7","739.72","739.74","739.76","739.78","739.8"],"Ask":[0,19,45,60,17,44,45,67,36,0,26,13,114,47,21,27,30,31,5,59,13,93,85,34,19,63,8],"Bid":[51,83,110,26,42,32,50,4,14,46,95,38,60,55,29,21,25,42,13,35,24,23,249,43,30,26,0],"symbol":"au2506","datetime":"2025-04-01 13:39:00","delta":-245.0,"close":739.6,"open":739.38,"high":739.8,"low":739.26,"volume":2430,"dj":0,"dayma":733.86,"delta累计":3320.0} +{"price":["739.16","739.18","739.2","739.22","739.24","739.26","739.28","739.3","739.32","739.34","739.36","739.38","739.4","739.42","739.44","739.46","739.48","739.5","739.52","739.54","739.56","739.6"],"Ask":[0,11,57,52,56,71,69,83,59,69,77,77,29,40,47,28,14,23,0,0,10,7],"Bid":[11,68,57,29,41,108,66,107,53,40,41,106,49,44,21,4,0,40,12,9,26,0],"symbol":"au2506","datetime":"2025-04-01 13:42:00","delta":-53.0,"close":739.3,"open":739.6,"high":739.6,"low":739.16,"volume":1982,"dj":0,"dayma":733.9225287356,"delta累计":3267.0} +{"price":["738.62","738.64","738.66","738.68","738.7","738.72","738.74","738.76","738.78","738.8","738.82","738.84","738.86","738.88","738.9","738.92","738.96","739.0","739.02","739.04","739.08","739.1","739.12","739.14","739.16","739.18","739.2","739.22","739.24","739.26","739.28","739.3"],"Ask":[0,62,68,31,143,145,110,28,44,48,95,51,19,50,15,13,55,0,89,12,0,17,58,26,34,20,0,12,8,33,4,21],"Bid":[15,72,146,140,93,54,66,35,70,117,50,50,34,27,7,58,24,30,55,59,7,0,38,50,65,3,23,23,0,11,7,0],"symbol":"au2506","datetime":"2025-04-01 13:45:00","delta":-118.0,"close":738.88,"open":739.3,"high":739.3,"low":738.62,"volume":3002,"dj":0,"dayma":733.9788636364,"delta累计":3149.0} +{"price":["738.4","738.44","738.46","738.48","738.5","738.52","738.54","738.56","738.58","738.6","738.62","738.64","738.66","738.68","738.7","738.72","738.74","738.76","738.78","738.8","738.82","738.84","738.86","738.88","738.9","738.92","738.94","738.96","738.98","739.0","739.02","739.04","739.06","739.08","739.1","739.12","739.14","739.16"],"Ask":[0,28,19,53,52,69,75,46,19,27,27,52,26,28,26,35,19,16,34,21,10,37,0,62,21,20,24,19,1,83,18,19,61,16,6,23,34,29],"Bid":[49,59,58,0,59,35,100,68,58,91,16,37,21,41,59,90,56,19,46,78,26,18,46,32,20,9,19,13,0,86,7,29,0,17,9,0,22,0],"symbol":"au2506","datetime":"2025-04-01 13:48:00","delta":-238.0,"close":738.56,"open":738.86,"high":739.16,"low":738.4,"volume":2929,"dj":0,"dayma":734.0303370787,"delta累计":2911.0} +{"price":["737.6","737.62","737.64","737.66","737.68","737.7","737.72","737.78","737.8","737.82","737.84","737.92","737.98","738.0","738.02","738.04","738.06","738.08","738.1","738.12","738.14","738.16","738.18","738.2","738.26","738.28","738.3","738.32","738.36","738.38","738.4","738.42","738.44","738.46","738.48","738.5","738.52","738.54","738.56","738.58","738.6","738.62","738.64","738.66","738.68","738.7","738.72"],"Ask":[33,100,14,90,32,148,53,27,0,0,0,20,0,23,0,9,0,22,83,71,42,130,0,45,0,0,79,49,33,0,0,11,21,0,18,18,30,33,56,26,23,27,66,40,97,93,19],"Bid":[36,46,0,16,0,175,35,27,22,19,29,23,62,74,69,0,8,106,89,20,31,34,24,12,27,32,11,46,0,21,33,5,14,11,0,23,99,28,61,47,7,114,36,52,68,36,0],"symbol":"au2506","datetime":"2025-04-01 13:51:00","delta":-47.0,"close":737.72,"open":738.56,"high":738.72,"low":737.6,"volume":3970,"dj":-1,"dayma":734.0713333333,"delta累计":2864.0} +{"price":["736.22","736.24","736.32","736.34","736.38","736.4","736.42","736.44","736.46","736.5","736.52","736.54","736.56","736.58","736.6","736.62","736.66","736.68","736.7","736.72","736.74","736.76","736.78","736.8","736.82","736.86","736.88","737.02","737.06","737.08","737.1","737.12","737.14","737.16","737.2","737.22","737.24","737.26","737.28","737.3","737.34","737.36","737.4","737.42","737.44","737.46","737.48","737.5","737.52","737.54","737.56","737.58","737.6","737.62","737.66","737.68","737.7","737.72","737.74","737.76","737.78","737.8","737.82","737.84","737.86","737.9","737.94","737.98","738.0","738.02","738.06"],"Ask":[43,254,146,0,0,158,30,0,31,57,119,137,43,24,0,0,0,15,0,16,0,68,142,77,0,154,56,0,0,22,21,113,49,25,0,0,29,94,27,23,0,0,0,36,11,89,13,111,46,69,6,100,29,0,39,18,121,49,117,72,37,41,54,0,14,18,32,18,44,0,22],"Bid":[30,146,59,43,23,101,57,30,0,129,34,103,14,0,19,12,35,31,44,30,79,177,128,6,107,33,96,38,124,98,26,0,7,23,51,15,14,36,42,45,39,39,34,101,22,37,13,147,83,95,21,76,51,7,96,20,58,108,37,78,29,91,47,46,0,0,46,41,49,14,0],"symbol":"au2506","datetime":"2025-04-01 13:54:00","delta":-431.0,"close":736.5,"open":737.74,"high":738.06,"low":736.22,"volume":7824,"dj":-2,"dayma":734.098021978,"delta累计":2433.0} +{"price":["735.48","735.5","735.52","735.56","735.58","735.6","735.64","735.66","735.68","735.7","735.72","735.74","735.76","735.78","735.8","735.82","735.84","735.86","735.88","735.9","735.92","735.94","735.96","735.98","736.0","736.02","736.04","736.06","736.08","736.1","736.12","736.14","736.16","736.18","736.2","736.22","736.24","736.26","736.28","736.3","736.32","736.34","736.36","736.38","736.4","736.42","736.46","736.48","736.5","736.52","736.54","736.56","736.58","736.6","736.62","736.64","736.66","736.68","736.7","736.72","736.74","736.8"],"Ask":[0,43,21,99,86,14,0,0,27,84,91,19,141,21,21,0,0,50,93,97,194,79,130,59,234,455,142,104,178,109,162,167,200,74,130,64,0,140,88,123,116,26,33,0,63,25,0,27,168,117,36,0,11,212,18,25,0,28,0,176,67,24],"Bid":[39,104,140,0,0,0,49,35,0,0,111,12,149,128,54,73,25,0,16,37,72,143,98,51,205,192,397,77,95,157,362,0,35,47,58,61,122,21,35,13,31,0,0,22,41,64,57,107,83,115,107,70,0,70,121,73,35,121,33,242,58,0],"symbol":"au2506","datetime":"2025-04-01 13:57:00","delta":248.0,"close":736.32,"open":736.52,"high":736.8,"low":735.48,"volume":11226,"dj":-2,"dayma":734.122173913,"delta累计":2681.0} +{"price":["736.12","736.14","736.16","736.18","736.2","736.22","736.24","736.26","736.28","736.3","736.32","736.34","736.36","736.38","736.4","736.42","736.44","736.46","736.48","736.5","736.52","736.54","736.56","736.58","736.6","736.62","736.64","736.66","736.68","736.7","736.72","736.74"],"Ask":[0,0,87,7,27,22,21,44,30,186,243,62,44,156,162,101,48,65,96,86,111,35,14,80,42,71,169,58,31,73,189,119],"Bid":[13,23,75,0,41,43,39,77,73,143,153,51,0,203,193,85,99,43,4,115,49,11,11,34,36,31,199,55,47,55,24,45],"symbol":"au2506","datetime":"2025-04-01 14:00:00","delta":409.0,"close":736.2,"open":736.34,"high":736.74,"low":736.12,"volume":5322,"dj":0,"dayma":734.144516129,"delta累计":3090.0} +{"price":["734.84","734.86","734.9","734.92","734.94","734.96","734.98","735.0","735.02","735.04","735.06","735.08","735.1","735.12","735.14","735.16","735.18","735.2","735.22","735.24","735.26","735.28","735.3","735.32","735.34","735.36","735.38","735.4","735.42","735.44","735.46","735.48","735.5","735.52","735.54","735.56","735.58","735.6","735.62","735.64","735.66","735.68","735.7","735.72","735.76","735.78","735.8","735.82","735.84","735.86","735.88","736.0","736.02","736.08","736.12"],"Ask":[0,0,0,108,22,29,0,0,22,64,106,0,235,65,80,141,281,191,380,273,127,194,247,0,26,26,36,54,0,64,47,37,15,16,5,124,20,90,118,73,90,0,83,0,42,0,33,0,0,21,97,0,0,0,0],"Bid":[41,54,145,42,32,37,294,170,0,0,426,36,200,78,342,263,171,241,213,65,55,126,51,78,101,101,43,150,24,10,193,65,278,45,63,130,70,199,17,50,56,42,264,39,149,40,172,34,25,96,34,47,17,80,43],"symbol":"au2506","datetime":"2025-04-01 14:03:00","delta":-2155.0,"close":735.76,"open":736.12,"high":736.12,"low":734.84,"volume":11201,"dj":-5,"dayma":734.1617021277,"delta累计":935.0} +{"price":["735.0","735.06","735.08","735.1","735.18","735.2","735.24","735.26","735.28","735.3","735.32","735.34","735.36","735.38","735.4","735.44","735.46","735.48","735.5","735.52","735.54","735.56","735.58","735.62","735.64","735.66","735.68","735.7","735.72","735.74","735.76","735.78","735.8","735.82","735.84","735.86","735.9","735.92","735.96","736.08","736.12","736.14","736.16","736.18","736.2","736.22","736.24","736.26","736.28","736.3","736.32","736.34","736.38","736.4","736.42","736.44","736.46","736.48","736.5","736.52","736.54","736.56","736.58"],"Ask":[0,35,82,0,131,113,78,0,25,0,54,17,0,105,100,106,53,28,80,0,16,70,87,0,0,30,13,42,79,34,14,132,116,139,95,62,43,37,65,37,0,33,84,22,168,38,45,2,54,73,86,14,23,21,112,114,101,664,167,228,52,122,25],"Bid":[27,69,0,19,31,135,0,42,48,27,179,87,136,0,258,92,30,48,0,22,36,0,0,13,41,0,69,14,86,96,60,34,99,59,20,0,173,13,0,0,22,0,16,33,121,0,57,14,14,123,8,60,17,53,228,214,40,105,23,156,91,57,0],"symbol":"au2506","datetime":"2025-04-01 14:06:00","delta":851.0,"close":736.58,"open":735.76,"high":736.58,"low":735.0,"volume":9125,"dj":0,"dayma":734.1871578947,"delta累计":1786.0} +{"price":["735.18","735.22","735.24","735.28","735.32","735.34","735.36","735.4","735.42","735.44","735.46","735.48","735.5","735.52","735.54","735.56","735.6","735.62","735.64","735.66","735.68","735.7","735.72","735.74","735.76","735.78","735.8","735.88","735.96","735.98","736.0","736.02","736.04","736.06","736.08","736.1","736.12","736.14","736.16","736.18","736.2","736.24","736.3","736.32","736.36","736.38","736.4","736.42","736.44","736.46","736.48","736.52","736.54","736.56","736.58","736.62","736.64","736.66","736.68","736.7","736.72","736.74","736.76","736.78","736.8","736.82","736.84","736.88"],"Ask":[0,0,84,16,159,52,0,33,85,8,18,0,29,17,0,9,40,117,63,0,140,43,0,67,111,107,38,0,0,0,0,9,64,147,76,146,190,175,51,17,18,0,11,54,0,19,0,0,18,11,0,38,17,0,18,14,43,37,68,45,0,23,157,25,31,37,0,15],"Bid":[76,39,0,0,46,0,16,45,37,0,0,18,15,13,55,13,58,242,21,27,183,44,34,46,11,18,45,6,27,13,32,61,132,189,205,87,98,89,54,15,0,25,28,33,7,0,18,9,15,28,5,19,71,67,7,89,56,50,16,84,29,0,83,174,19,0,20,0],"symbol":"au2506","datetime":"2025-04-01 14:09:00","delta":-252.0,"close":735.5,"open":736.58,"high":736.88,"low":735.18,"volume":7004,"dj":-3,"dayma":734.2008333333,"delta累计":1534.0} +{"price":["734.94","734.96","734.98","735.0","735.02","735.04","735.06","735.08","735.1","735.12","735.14","735.16","735.18","735.2","735.22","735.24","735.26","735.28","735.3","735.32","735.34","735.36","735.38","735.4","735.42","735.44","735.46","735.48","735.5","735.52","735.54"],"Ask":[0,88,32,55,62,103,0,0,43,102,84,51,56,85,58,87,136,65,103,192,201,59,87,80,63,42,35,119,165,53,10],"Bid":[36,57,0,59,58,67,86,111,44,42,25,65,147,42,77,120,87,99,104,110,62,0,144,76,44,88,32,166,74,0,0],"symbol":"au2506","datetime":"2025-04-01 14:12:00","delta":194.0,"close":735.44,"open":735.52,"high":735.54,"low":734.94,"volume":5160,"dj":0,"dayma":734.2136082474,"delta累计":1728.0} +{"price":["735.2","735.24","735.26","735.28","735.3","735.32","735.34","735.36","735.38","735.4","735.42","735.44","735.46","735.48","735.5","735.52","735.54","735.56","735.58","735.6","735.62","735.64","735.66","735.68","735.7","735.72","735.74"],"Ask":[0,43,99,7,108,18,14,15,25,16,73,33,33,85,174,106,96,84,37,172,41,54,115,40,0,18,7],"Bid":[19,52,44,79,10,29,18,60,21,122,24,21,74,177,140,99,120,114,38,102,37,61,81,14,25,17,0],"symbol":"au2506","datetime":"2025-04-01 14:15:00","delta":-85.0,"close":735.54,"open":735.5,"high":735.74,"low":735.2,"volume":3530,"dj":0,"dayma":734.2271428571,"delta累计":1643.0} +{"price":["735.38","735.4","735.42","735.44","735.46","735.48","735.5","735.52","735.54","735.56","735.58","735.6","735.62","735.64","735.66","735.68","735.72","735.74","735.8","735.82","735.88","735.9","735.92","735.94","735.96","735.98","736.0","736.02","736.04","736.06","736.08","736.1","736.12","736.14","736.16","736.18","736.2","736.22","736.24","736.26","736.28","736.3","736.32","736.34","736.36","736.38","736.4","736.42","736.44"],"Ask":[0,17,17,0,16,29,12,2,14,18,36,27,7,6,0,44,63,35,42,6,12,0,54,34,117,35,35,58,0,87,32,42,53,14,0,20,29,36,67,0,15,14,64,65,42,32,45,47,10],"Bid":[26,43,27,5,0,57,26,14,25,61,10,13,0,0,54,0,4,32,27,30,22,39,11,24,43,58,0,38,67,120,87,0,23,11,47,50,19,54,0,11,57,15,127,16,0,28,58,22,0],"symbol":"au2506","datetime":"2025-04-01 14:18:00","delta":-51.0,"close":736.26,"open":735.54,"high":736.44,"low":735.38,"volume":3600,"dj":0,"dayma":734.2476767677,"delta累计":1592.0} +{"price":["735.8","735.82","735.84","735.86","735.88","735.9","735.92","735.94","735.96","735.98","736.0","736.02","736.04","736.06","736.08","736.1","736.12","736.14","736.16","736.18","736.2","736.24","736.26","736.28","736.32","736.34","736.36","736.38","736.4","736.42","736.44","736.46","736.48","736.5","736.52","736.54","736.56","736.58","736.6","736.62","736.64"],"Ask":[0,0,16,49,32,0,20,38,18,75,43,100,0,43,42,52,41,7,7,11,14,18,0,10,0,0,7,14,30,12,46,27,108,99,44,2,72,77,39,11,16],"Bid":[51,26,17,74,7,7,73,87,41,218,91,46,25,74,121,75,12,0,20,25,23,19,33,39,15,41,56,26,63,31,88,39,94,54,72,18,68,25,26,0,0],"symbol":"au2506","datetime":"2025-04-01 14:21:00","delta":-680.0,"close":735.84,"open":736.28,"high":736.64,"low":735.8,"volume":3594,"dj":-4,"dayma":734.2636,"delta累计":912.0} +{"price":["735.82","735.84","735.86","735.88","735.9","735.92","735.94","735.96","735.98","736.0","736.02","736.04","736.06","736.08","736.1","736.18","736.22","736.24","736.26","736.28","736.3","736.32","736.34","736.36","736.38","736.4"],"Ask":[0,15,24,54,29,8,34,10,37,14,3,23,8,28,9,0,0,53,90,80,99,65,51,23,113,36],"Bid":[9,30,7,17,14,3,43,19,19,34,5,0,5,4,21,9,22,53,55,62,59,114,83,26,59,0],"symbol":"au2506","datetime":"2025-04-01 14:24:00","delta":134.0,"close":736.3,"open":735.84,"high":736.4,"low":735.82,"volume":1977,"dj":1,"dayma":734.2837623762,"delta累计":1046.0} +{"price":["736.32","736.34","736.36","736.38","736.4","736.42","736.44","736.46","736.48","736.5","736.52","736.54","736.58","736.6","736.62","736.64","736.66","736.68","736.7","736.72","736.74","736.76","736.78","736.8","736.82","736.84","736.86","736.88","736.9","736.94","736.98","737.0"],"Ask":[0,13,17,33,56,91,48,92,70,51,16,20,6,43,0,17,8,41,127,109,47,34,25,47,54,84,31,18,19,0,55,45],"Bid":[5,14,11,19,68,35,57,68,23,57,0,7,20,0,8,0,4,123,89,70,64,65,33,77,93,23,19,0,56,25,94,20],"symbol":"au2506","datetime":"2025-04-01 14:27:00","delta":70.0,"close":736.94,"open":736.36,"high":737.0,"low":736.32,"volume":2852,"dj":0,"dayma":734.3098039216,"delta累计":1116.0} +{"price":["736.68","736.7","736.72","736.76","736.78","736.8","736.82","736.84","736.92","736.94","736.96","736.98","737.0","737.02","737.04","737.06","737.08","737.1","737.12","737.14","737.16","737.18","737.2","737.22","737.24","737.26","737.28","737.3","737.32","737.34","737.36"],"Ask":[0,0,0,8,0,42,0,24,0,0,0,36,29,90,13,39,73,119,137,49,121,12,106,182,67,43,32,130,11,79,9],"Bid":[31,26,8,0,30,18,12,0,14,38,20,29,31,27,47,68,149,127,113,66,28,30,196,129,68,57,143,53,45,0,0],"symbol":"au2506","datetime":"2025-04-01 14:30:00","delta":-152.0,"close":736.68,"open":736.94,"high":737.36,"low":736.68,"volume":3577,"dj":0,"dayma":734.332815534,"delta累计":964.0} +{"price":["736.24","736.3","736.32","736.36","736.38","736.4","736.42","736.44","736.46","736.48","736.5","736.52","736.54","736.56","736.58","736.6","736.62","736.64","736.66","736.68","736.7","736.72","736.74","736.76","736.78","736.8","736.82","736.84","736.86","736.88"],"Ask":[0,22,15,120,0,156,0,90,77,91,95,66,32,60,27,77,44,32,146,79,49,44,14,1,40,13,3,26,22,84],"Bid":[13,0,0,73,111,82,31,27,29,49,18,34,13,26,2,88,31,66,60,47,20,0,28,32,24,0,37,22,34,23],"symbol":"au2506","datetime":"2025-04-01 14:33:00","delta":505.0,"close":736.8,"open":736.68,"high":736.88,"low":736.24,"volume":2946,"dj":0,"dayma":734.3565384615,"delta累计":1469.0} +{"price":["736.64","736.66","736.68","736.7","736.72","736.74","736.76","736.78","736.8","736.82","736.84","736.86","736.88","736.9","736.92","736.94","736.96","736.98","737.0","737.02","737.04","737.06","737.08","737.1"],"Ask":[0,45,0,10,13,32,41,14,5,19,44,47,58,18,57,57,41,45,59,34,17,25,12,4],"Bid":[8,46,11,9,7,33,10,0,30,12,23,5,41,62,36,31,74,31,50,31,1,65,7,0],"symbol":"au2506","datetime":"2025-04-01 14:36:00","delta":74.0,"close":736.84,"open":736.82,"high":737.1,"low":736.62,"volume":1458,"dj":0,"dayma":734.3801904762,"delta累计":1543.0} +{"price":["736.3","736.32","736.34","736.36","736.38","736.4","736.42","736.44","736.46","736.48","736.5","736.52","736.54","736.56","736.58","736.6","736.62","736.64","736.66","736.68","736.7","736.72","736.74","736.76","736.78","736.82","736.84","736.86","736.88","736.9","736.92","736.94"],"Ask":[0,32,13,0,17,92,47,170,61,74,36,15,13,12,7,30,11,27,54,23,27,18,21,58,21,0,30,32,22,17,2,2],"Bid":[2,49,0,20,38,86,34,46,81,33,20,39,5,8,11,50,17,8,50,33,36,61,9,69,1,21,49,11,1,0,40,0],"symbol":"au2506","datetime":"2025-04-01 14:39:00","delta":56.0,"close":736.32,"open":736.82,"high":736.94,"low":736.3,"volume":2066,"dj":0,"dayma":734.398490566,"delta累计":1599.0} +{"price":["736.04","736.06","736.08","736.1","736.12","736.14","736.16","736.18","736.2","736.22","736.24","736.26","736.28","736.3","736.32","736.34","736.36","736.38","736.4","736.42","736.44","736.46","736.48","736.5"],"Ask":[0,12,31,19,0,56,0,61,45,35,27,2,24,171,82,49,48,70,37,41,46,47,100,5],"Bid":[75,14,0,27,14,14,72,43,71,48,45,26,38,26,116,56,23,77,17,23,23,60,3,0],"symbol":"au2506","datetime":"2025-04-01 14:42:00","delta":97.0,"close":736.34,"open":736.32,"high":736.5,"low":736.04,"volume":2095,"dj":0,"dayma":734.416635514,"delta累计":1696.0} +{"price":["735.92","735.94","735.96","735.98","736.0","736.02","736.04","736.06","736.08","736.1","736.12","736.14","736.16","736.18","736.2","736.22","736.24","736.26","736.28","736.3","736.32","736.34","736.36","736.38","736.4","736.42","736.44","736.46","736.48","736.5","736.52","736.54","736.56","736.58","736.6","736.62","736.64","736.66","736.68","736.72"],"Ask":[9,22,77,32,30,41,25,55,0,2,31,20,28,20,2,8,59,10,8,8,49,10,27,53,5,12,57,7,32,10,2,10,16,30,29,15,15,37,16,5],"Bid":[12,57,25,57,108,61,19,25,37,42,51,15,26,37,22,38,53,23,47,17,17,33,10,31,57,3,26,15,17,14,17,8,17,14,4,6,20,8,15,0],"symbol":"au2506","datetime":"2025-04-01 14:45:00","delta":-180.0,"close":736.04,"open":736.36,"high":736.72,"low":735.92,"volume":2211,"dj":0,"dayma":734.4316666667,"delta累计":1516.0} +{"price":["735.54","735.56","735.58","735.6","735.62","735.64","735.66","735.68","735.7","735.72","735.74","735.76","735.78","735.8","735.82","735.84","735.86","735.88","735.9","735.92","735.94","735.96","735.98","736.0","736.02","736.04","736.06","736.08","736.1","736.12","736.14","736.16"],"Ask":[0,45,15,41,21,18,19,31,31,40,19,8,14,0,19,33,141,28,13,26,18,3,17,15,26,39,27,61,97,56,73,13],"Bid":[65,47,0,17,21,43,35,76,56,19,18,26,29,26,51,118,57,12,16,32,17,51,59,32,28,70,54,88,90,7,10,3],"symbol":"au2506","datetime":"2025-04-01 14:48:00","delta":-266.0,"close":735.82,"open":736.0,"high":736.16,"low":735.54,"volume":2490,"dj":0,"dayma":734.4444036697,"delta累计":1250.0} +{"price":["735.82","735.84","735.88","735.94","735.96","735.98","736.0","736.02","736.04","736.06","736.08","736.1","736.12","736.14","736.16","736.18","736.2","736.22","736.24","736.26","736.28","736.3","736.32","736.34","736.36","736.38","736.4","736.42","736.44","736.46","736.48"],"Ask":[1,4,18,20,3,14,33,21,18,11,35,46,84,62,29,5,14,0,11,16,35,13,26,106,38,39,59,76,118,21,93],"Bid":[0,0,0,4,32,20,38,7,24,9,52,14,11,18,33,4,7,3,17,9,43,20,141,88,46,38,49,132,96,8,0],"symbol":"au2506","datetime":"2025-04-01 14:51:00","delta":106.0,"close":736.46,"open":735.82,"high":736.48,"low":735.82,"volume":2249,"dj":1,"dayma":734.4627272727,"delta累计":1356.0} +{"price":["736.16","736.2","736.24","736.26","736.28","736.3","736.32","736.34","736.36","736.38","736.4","736.42","736.44","736.46","736.48","736.5","736.58","736.6","736.62","736.64","736.66","736.68","736.7","736.72","736.74","736.76","736.78","736.8","736.82"],"Ask":[0,17,0,6,11,8,6,17,0,98,95,79,115,90,125,39,36,21,47,0,11,51,99,3,15,41,72,60,21],"Bid":[58,3,9,6,0,41,12,37,23,125,153,33,37,24,60,41,3,13,0,36,13,16,33,16,30,38,28,17,0],"symbol":"au2506","datetime":"2025-04-01 14:54:00","delta":278.0,"close":736.78,"open":736.46,"high":736.82,"low":736.16,"volume":2309,"dj":0,"dayma":734.4836036036,"delta累计":1634.0} +{"price":["736.24","736.26","736.28","736.3","736.32","736.34","736.36","736.38","736.4","736.42","736.44","736.46","736.48","736.5","736.52","736.54","736.56","736.58","736.6","736.62","736.64","736.66","736.7","736.76","736.78","736.8","736.82","736.84","736.86","736.88","736.9","736.92"],"Ask":[0,24,37,83,11,14,38,11,9,27,36,46,30,58,21,82,5,18,34,0,26,4,21,0,20,22,22,15,21,20,48,64],"Bid":[34,61,23,7,82,24,52,19,28,117,74,34,57,68,31,17,66,33,35,18,0,0,0,3,44,68,9,3,25,46,33,13],"symbol":"au2506","datetime":"2025-04-01 14:57:00","delta":-257.0,"close":736.36,"open":736.78,"high":736.92,"low":736.24,"volume":2243,"dj":0,"dayma":734.5003571429,"delta累计":1377.0} +{"price":["736.2","736.24","736.26","736.28","736.3","736.32","736.34","736.36","736.38","736.4","736.42","736.44","736.46","736.48","736.5","736.52","736.54","736.56","736.58","736.6","736.62","736.66","736.68","736.7","736.72","736.74","736.76","736.78","736.8","736.82","736.84","736.86","736.88","736.9","736.92","736.94","736.96","736.98","737.0","737.02","737.04","737.06","737.08","737.1","737.12","737.14","737.16"],"Ask":[28,60,10,54,0,35,0,36,15,41,30,48,47,22,31,0,25,35,87,85,168,89,57,12,224,0,111,0,0,183,26,64,88,255,169,42,62,37,79,54,133,69,85,113,94,105,32],"Bid":[79,0,0,23,36,48,19,88,56,76,104,72,0,39,0,28,0,30,74,207,82,0,34,49,17,56,0,50,24,158,73,156,109,321,51,42,27,23,74,100,79,117,33,26,67,21,0],"symbol":"au2506","datetime":"2025-04-01 21:03:00","delta":272.0,"close":737.14,"open":737.1,"high":737.16,"low":736.2,"volume":6707,"dj":0,"dayma":737.3941176471,"delta累计":641.0} +{"price":["737.0","737.02","737.04","737.06","737.08","737.1","737.12","737.14","737.16","737.18","737.2","737.22","737.24","737.26","737.28","737.3","737.32","737.34","737.36","737.38","737.4","737.42","737.44","737.46","737.48"],"Ask":[45,12,10,23,20,33,46,31,9,60,144,79,295,193,145,258,8,96,109,226,126,37,7,47,49],"Bid":[25,20,22,63,41,4,198,57,44,133,94,127,202,166,134,101,46,157,196,148,106,65,0,26,36],"symbol":"au2506","datetime":"2025-04-01 21:06:00","delta":-103.0,"close":737.24,"open":737.16,"high":737.48,"low":737.0,"volume":4792,"dj":0,"dayma":737.3911538462,"delta累计":538.0} +{"price":["737.1","737.12","737.14","737.16","737.18","737.2","737.22","737.24","737.26","737.28","737.3","737.32","737.34","737.36","737.38","737.4","737.42","737.44","737.46","737.48","737.5","737.52","737.54","737.56","737.58","737.6","737.62","737.64","737.66","737.68","737.7","737.72","737.74","737.76","737.78","737.8"],"Ask":[5,37,15,32,84,76,27,62,88,27,46,53,33,48,125,49,42,8,35,152,113,12,22,145,51,66,36,0,0,80,115,23,23,15,12,13],"Bid":[14,8,9,39,67,75,34,22,59,60,21,64,5,60,88,7,65,19,20,207,185,8,50,19,72,26,58,51,9,0,35,5,20,46,19,0],"symbol":"au2506","datetime":"2025-04-01 21:09:00","delta":224.0,"close":737.78,"open":737.22,"high":737.8,"low":737.1,"volume":3634,"dj":0,"dayma":737.398490566,"delta累计":762.0} +{"price":["737.3","737.32","737.34","737.36","737.38","737.4","737.42","737.44","737.46","737.48","737.5","737.54","737.56","737.58","737.6","737.62","737.64","737.66","737.68","737.7","737.72","737.74","737.76","737.78","737.8","737.82","737.84","737.86","737.88","737.9","737.92","737.94","737.96","737.98","738.0","738.02","738.04","738.06","738.08"],"Ask":[0,27,14,29,131,59,55,28,93,10,5,32,31,14,41,23,123,0,17,12,11,28,47,48,34,196,22,28,35,12,6,163,66,106,79,106,107,173,68],"Bid":[6,25,39,67,81,91,57,10,27,31,73,42,39,39,10,51,14,23,18,13,44,42,59,62,127,104,36,0,33,0,36,106,193,88,69,49,57,38,0],"symbol":"au2506","datetime":"2025-04-01 21:12:00","delta":180.0,"close":737.48,"open":737.78,"high":738.08,"low":737.3,"volume":4413,"dj":0,"dayma":737.4,"delta累计":942.0} +{"price":["737.02","737.04","737.06","737.08","737.1","737.12","737.14","737.16","737.18","737.2","737.22","737.24","737.26","737.28","737.3","737.32","737.34","737.36","737.38","737.4","737.42","737.46","737.48","737.5","737.52","737.54","737.56","737.58","737.6","737.62"],"Ask":[36,0,88,15,2,90,104,53,48,15,47,16,68,98,39,68,55,59,52,21,7,46,4,5,9,2,14,33,25,48],"Bid":[76,10,84,52,59,66,152,99,28,81,18,118,61,134,45,45,72,102,46,8,68,0,58,1,5,16,31,57,14,10],"symbol":"au2506","datetime":"2025-04-01 21:15:00","delta":-449.0,"close":737.16,"open":737.48,"high":737.62,"low":737.02,"volume":2987,"dj":0,"dayma":737.3956363636,"delta累计":493.0} +{"price":["736.72","736.74","736.76","736.78","736.8","736.82","736.84","736.86","736.88","736.9","736.92","736.94","736.96","736.98","737.0","737.02","737.04","737.06","737.08","737.1","737.12","737.14","737.16","737.18","737.2","737.22","737.24","737.26","737.28","737.3"],"Ask":[0,0,120,0,15,99,0,24,31,83,91,21,53,185,124,50,78,55,30,127,74,47,35,73,20,105,0,9,20,18],"Bid":[24,42,25,9,50,0,63,0,0,113,88,119,52,101,85,64,157,32,59,188,32,15,97,73,30,21,12,36,17,0],"symbol":"au2506","datetime":"2025-04-01 21:18:00","delta":-17.0,"close":737.12,"open":737.22,"high":737.3,"low":736.72,"volume":3434,"dj":0,"dayma":737.3907142857,"delta累计":476.0} +{"price":["736.34","736.36","736.38","736.4","736.42","736.44","736.52","736.54","736.56","736.58","736.6","736.62","736.64","736.66","736.68","736.7","736.76","736.78","736.8","736.82","736.84","736.86","736.88","736.9","736.92","736.94","736.96","736.98","737.0","737.02","737.04","737.06","737.08","737.1","737.12","737.14","737.16","737.18","737.2"],"Ask":[0,14,79,33,108,0,36,0,9,68,43,0,23,59,74,0,0,0,58,14,23,41,89,45,17,8,26,75,104,33,79,12,18,26,49,0,27,78,0],"Bid":[54,62,58,0,23,21,13,50,16,12,23,79,7,7,12,32,18,16,54,37,42,45,21,45,62,40,66,105,59,123,26,48,16,48,56,6,0,0,5],"symbol":"au2506","datetime":"2025-04-01 21:21:00","delta":-39.0,"close":736.42,"open":737.16,"high":737.2,"low":736.34,"volume":3101,"dj":-1,"dayma":737.3736842105,"delta累计":437.0} +{"price":["735.76","735.78","735.8","735.82","735.84","735.86","735.88","735.9","735.92","735.94","735.96","735.98","736.0","736.02","736.04","736.06","736.08","736.1","736.12","736.14","736.16","736.18","736.2","736.22","736.24","736.26","736.28","736.3","736.32","736.34","736.36","736.38","736.4","736.42","736.44","736.46","736.48","736.5","736.52"],"Ask":[0,36,0,12,150,32,21,15,0,71,60,71,11,13,64,19,137,89,12,143,103,60,21,31,37,88,38,68,93,26,90,54,83,50,18,15,28,23,14],"Bid":[39,28,46,126,122,0,49,31,27,32,52,60,27,118,22,0,83,83,137,174,36,103,93,76,0,73,105,53,49,65,129,112,94,36,2,42,37,35,0],"symbol":"au2506","datetime":"2025-04-01 21:24:00","delta":-500.0,"close":735.8,"open":736.4,"high":736.52,"low":735.76,"volume":4890,"dj":0,"dayma":737.3465517241,"delta累计":-63.0} +{"price":["735.7","735.72","735.74","735.76","735.78","735.8","735.82","735.84","735.86","735.88","735.9","735.92","735.94","735.96","735.98","736.0","736.02","736.04","736.06","736.08","736.1","736.12","736.14","736.16","736.18","736.2","736.22","736.24","736.26","736.28","736.3","736.32","736.34"],"Ask":[0,0,0,59,25,35,66,6,42,23,94,19,64,150,140,75,39,36,374,37,80,48,146,12,66,126,31,18,53,27,4,43,25],"Bid":[78,69,47,118,53,72,38,13,7,32,68,81,118,98,5,128,11,69,42,122,107,82,103,105,140,107,14,0,40,60,0,60,0],"symbol":"au2506","datetime":"2025-04-01 21:27:00","delta":-124.0,"close":735.9,"open":735.82,"high":736.34,"low":735.7,"volume":4361,"dj":0,"dayma":737.3220338983,"delta累计":-187.0} +{"price":["735.6","735.64","735.66","735.68","735.7","735.72","735.74","735.76","735.78","735.8","735.82","735.84","735.86","735.88","735.9","735.92","735.94","735.96","735.98","736.0","736.02","736.04","736.06","736.08","736.1","736.12","736.14","736.16","736.18"],"Ask":[14,41,0,49,11,43,43,0,21,55,16,20,40,57,133,77,28,39,80,11,47,152,148,37,38,36,38,6,58],"Bid":[54,51,18,47,31,36,61,21,51,95,46,9,65,51,235,79,28,98,51,32,76,107,54,65,24,22,41,2,20],"symbol":"au2506","datetime":"2025-04-01 21:30:00","delta":-232.0,"close":735.94,"open":735.88,"high":736.18,"low":735.6,"volume":3195,"dj":0,"dayma":737.299,"delta累计":-419.0} +{"price":["735.62","735.64","735.66","735.68","735.7","735.72","735.74","735.76","735.78","735.8","735.82","735.84","735.86","735.88","735.9","735.92","735.94","735.96","735.98","736.0","736.02","736.04","736.06","736.08","736.1","736.12","736.14","736.16","736.18","736.2","736.24","736.26","736.32","736.34","736.36","736.38","736.4","736.42","736.44","736.46","736.48","736.5","736.52","736.54","736.56","736.58","736.6"],"Ask":[0,10,50,23,27,34,8,0,26,0,89,13,25,124,8,47,53,10,53,25,115,75,73,58,106,123,74,36,82,50,11,6,59,43,148,80,72,58,59,42,118,100,52,117,49,43,60],"Bid":[22,11,22,0,34,23,0,14,79,43,101,74,25,12,97,49,41,8,32,87,48,88,74,158,74,61,8,21,26,0,0,0,31,39,112,146,24,102,64,43,52,137,106,4,12,7,0],"symbol":"au2506","datetime":"2025-04-01 21:33:00","delta":323.0,"close":736.5,"open":735.9,"high":736.6,"low":735.62,"volume":5341,"dj":2,"dayma":737.2859016393,"delta累计":-96.0} +{"price":["736.28","736.3","736.32","736.34","736.36","736.38","736.4","736.42","736.44","736.46","736.48","736.5","736.52","736.54","736.56","736.58","736.6","736.62","736.64","736.66","736.68","736.7","736.72","736.74","736.76"],"Ask":[32,32,96,57,62,35,62,14,45,51,51,15,24,19,156,47,66,107,152,84,104,75,149,35,17],"Bid":[20,52,84,80,78,88,44,39,21,22,49,19,84,169,80,104,82,73,153,108,231,100,56,20,3],"symbol":"au2506","datetime":"2025-04-01 21:36:00","delta":-272.0,"close":736.3,"open":736.5,"high":736.76,"low":736.28,"volume":3762,"dj":0,"dayma":737.27,"delta累计":-368.0} +{"price":["736.0","736.02","736.04","736.06","736.08","736.1","736.12","736.14","736.16","736.18","736.2","736.22","736.24","736.26","736.28","736.3","736.32","736.34","736.36","736.38","736.4","736.42","736.44","736.46","736.48","736.5","736.52","736.54","736.56"],"Ask":[33,0,22,22,28,61,8,93,23,15,56,34,29,64,32,62,31,3,16,13,76,19,6,15,121,96,65,46,89],"Bid":[78,82,67,24,38,73,24,34,55,38,62,63,31,4,52,70,14,11,23,37,59,20,25,111,142,52,46,8,40],"symbol":"au2506","datetime":"2025-04-01 21:39:00","delta":-205.0,"close":736.2,"open":736.3,"high":736.56,"low":735.98,"volume":2927,"dj":-1,"dayma":737.253015873,"delta累计":-573.0} +{"price":["736.1","736.12","736.14","736.16","736.18","736.2","736.22","736.24","736.28","736.3","736.34","736.38","736.4","736.42","736.44","736.46","736.48","736.5","736.52","736.54","736.56","736.58","736.6","736.62","736.64","736.66","736.68","736.7","736.72","736.76","736.78","736.8","736.82","736.84","736.86","736.88","736.9","736.92","736.94","736.96","736.98","737.0","737.02","737.04","737.06","737.08","737.1","737.12","737.14","737.16","737.18","737.22","737.24"],"Ask":[0,0,52,19,14,0,53,53,12,9,2,4,0,0,7,7,57,80,41,117,90,57,35,15,78,0,22,12,19,10,28,88,0,30,10,41,43,15,96,63,50,85,54,27,53,44,88,39,25,23,21,0,75],"Bid":[11,11,70,41,0,36,17,6,0,0,0,0,3,30,31,10,45,74,16,110,37,83,9,6,25,33,0,12,0,0,54,0,11,33,25,99,34,84,93,54,24,18,34,74,0,53,45,54,0,29,0,49,0],"symbol":"au2506","datetime":"2025-04-01 21:42:00","delta":280.0,"close":737.0,"open":736.22,"high":737.26,"low":736.1,"volume":3737,"dj":0,"dayma":737.2490625,"delta累计":-293.0} +{"price":["736.64","736.68","736.7","736.72","736.74","736.76","736.78","736.8","736.82","736.84","736.86","736.88","736.9","736.92","736.94","736.96","736.98","737.0","737.02","737.04"],"Ask":[0,17,32,37,26,0,9,32,43,77,51,73,58,41,32,102,72,178,96,20],"Bid":[20,4,23,55,47,4,30,73,80,48,102,60,57,69,44,135,95,71,14,0],"symbol":"au2506","datetime":"2025-04-01 21:45:00","delta":-35.0,"close":736.74,"open":737.0,"high":737.04,"low":736.64,"volume":2150,"dj":0,"dayma":737.2412307692,"delta累计":-328.0} +{"price":["736.44","736.46","736.48","736.5","736.52","736.54","736.56","736.58","736.6","736.62","736.64","736.66","736.68","736.7","736.72","736.74","736.78","736.8","736.82","736.84","736.86","736.88","736.9","736.92","736.94","736.96","736.98","737.0"],"Ask":[0,0,15,50,60,47,72,85,96,114,50,61,37,27,0,10,10,0,16,31,58,55,48,59,30,61,22,10],"Bid":[89,51,37,85,54,125,45,39,91,52,69,62,27,14,9,8,0,2,52,48,71,41,48,27,60,37,0,0],"symbol":"au2506","datetime":"2025-04-01 21:48:00","delta":-119.0,"close":736.9,"open":736.72,"high":737.0,"low":736.44,"volume":2558,"dj":0,"dayma":737.2360606061,"delta累计":-447.0} +{"price":["736.54","736.56","736.58","736.6","736.62","736.64","736.66","736.68","736.7","736.72","736.74","736.76","736.8","736.82","736.84","736.86","736.88","736.9","736.92","736.94","736.96","736.98","737.0","737.02","737.04","737.06","737.08","737.1","737.12","737.14","737.16","737.18","737.2"],"Ask":[29,23,83,47,18,15,48,11,57,11,6,15,25,0,27,26,20,6,14,3,22,52,70,32,126,114,109,120,25,20,12,41,6],"Bid":[56,113,16,29,35,52,0,53,35,28,0,9,13,17,90,30,20,19,74,47,36,47,12,36,134,151,144,48,0,19,27,9,0],"symbol":"au2506","datetime":"2025-04-01 21:51:00","delta":-166.0,"close":736.7,"open":736.86,"high":737.2,"low":736.54,"volume":2910,"dj":0,"dayma":737.2280597015,"delta累计":-613.0} +{"price":["736.62","736.64","736.66","736.68","736.7","736.72","736.74","736.76","736.78","736.8","736.82","736.84","736.86","736.88","736.9","736.92","736.94","736.96","736.98","737.0","737.02","737.04","737.06","737.08","737.1","737.12"],"Ask":[0,30,40,32,38,23,11,36,79,112,89,89,73,49,53,16,45,12,52,29,15,0,11,8,2,11],"Bid":[26,53,42,104,7,46,24,18,57,101,67,48,113,19,38,11,29,61,16,10,19,1,17,79,11,0],"symbol":"au2506","datetime":"2025-04-01 21:54:00","delta":-62.0,"close":736.88,"open":736.7,"high":737.12,"low":736.62,"volume":2131,"dj":0,"dayma":737.2229411765,"delta累计":-675.0} +{"price":["736.76","736.78","736.8","736.82","736.84","736.86","736.88","736.9","736.92","736.94","736.96","736.98","737.0","737.02","737.04","737.06","737.08","737.1","737.12"],"Ask":[3,17,43,7,14,10,0,94,82,31,41,30,73,90,56,64,50,30,31],"Bid":[0,32,43,7,5,21,30,90,72,15,11,18,128,70,64,10,18,51,34],"symbol":"au2506","datetime":"2025-04-01 21:57:00","delta":47.0,"close":736.84,"open":736.88,"high":737.12,"low":736.76,"volume":1607,"dj":0,"dayma":737.2173913043,"delta累计":-628.0} +{"price":["736.78","736.8","736.82","736.84","736.86","736.88","736.9","736.92","736.94","736.96","736.98","737.0","737.02","737.04","737.06","737.08","737.1"],"Ask":[0,12,5,12,13,2,46,33,58,98,50,64,52,79,29,28,58],"Bid":[20,21,4,4,0,20,47,39,82,53,34,105,42,54,38,19,0],"symbol":"au2506","datetime":"2025-04-01 22:00:00","delta":57.0,"close":737.1,"open":736.82,"high":737.1,"low":736.78,"volume":1293,"dj":0,"dayma":737.2157142857,"delta累计":-571.0} +{"price":["736.1","736.12","736.18","736.2","736.22","736.26","736.28","736.3","736.32","736.34","736.36","736.38","736.4","736.42","736.44","736.46","736.48","736.52","736.62","736.64","736.74","736.76","736.78","736.8","736.82","736.84","736.86","736.88","736.9","736.94","736.96","737.0","737.02","737.04","737.06","737.08","737.1","737.12","737.14","737.16","737.18","737.2","737.22","737.24","737.26","737.28","737.3","737.32","737.34","737.36","737.38","737.4","737.42","737.44","737.46","737.48","737.5"],"Ask":[0,26,0,64,75,18,59,30,186,62,59,13,53,19,61,16,22,0,0,0,0,0,24,0,0,0,53,65,17,10,23,7,23,14,0,21,58,59,109,42,48,157,31,57,8,63,36,43,39,85,90,91,42,79,10,49,65],"Bid":[20,37,95,90,18,27,84,109,121,70,98,121,100,88,19,38,140,38,50,34,11,16,0,22,20,47,8,63,10,15,5,25,42,8,16,100,40,130,78,0,60,94,127,124,23,28,38,29,47,63,154,101,99,47,0,36,0],"symbol":"au2506","datetime":"2025-04-01 22:03:00","delta":-842.0,"close":736.42,"open":737.1,"high":737.5,"low":736.1,"volume":6139,"dj":-3,"dayma":737.2045070423,"delta累计":-1413.0} +{"price":["736.18","736.2","736.22","736.24","736.26","736.28","736.3","736.34","736.36","736.38","736.4","736.42","736.44","736.46","736.48","736.5","736.52","736.54","736.56","736.58","736.6","736.62","736.64","736.66","736.68","736.7","736.72","736.74","736.78","736.8","736.82","736.84","736.86","736.88","736.9","736.94","736.96","736.98","737.0","737.02","737.04","737.06","737.08"],"Ask":[0,54,2,45,19,33,30,33,0,5,9,7,31,43,36,75,6,22,36,49,79,119,88,27,70,54,35,56,4,8,54,0,61,81,38,11,7,33,8,24,58,18,14],"Bid":[11,74,0,7,37,0,0,10,6,0,14,15,1,8,33,11,24,65,14,5,155,180,95,30,75,57,13,0,28,19,57,30,53,54,9,16,16,64,3,33,28,0,0],"symbol":"au2506","datetime":"2025-04-01 22:06:00","delta":132.0,"close":736.96,"open":736.44,"high":737.08,"low":736.18,"volume":3290,"dj":0,"dayma":737.2011111111,"delta累计":-1281.0} +{"price":["736.6","736.62","736.64","736.66","736.68","736.7","736.72","736.74","736.76","736.78","736.8","736.82","736.84","736.86","736.88","736.9","736.92","736.94","736.96","736.98","737.0","737.02","737.04","737.06","737.08","737.1","737.14","737.16","737.2"],"Ask":[12,33,18,21,16,54,12,28,68,100,69,58,31,61,117,40,16,29,63,47,68,36,34,24,0,97,29,18,8],"Bid":[33,12,77,51,16,31,16,59,153,59,104,36,24,73,112,99,76,30,35,5,49,25,18,33,26,14,45,19,0],"symbol":"au2506","datetime":"2025-04-01 22:09:00","delta":-123.0,"close":736.66,"open":736.96,"high":737.2,"low":736.6,"volume":2764,"dj":0,"dayma":737.1936986301,"delta累计":-1404.0} +{"price":["736.06","736.08","736.1","736.12","736.14","736.16","736.18","736.2","736.22","736.24","736.26","736.28","736.3","736.32","736.34","736.36","736.38","736.4","736.42","736.44","736.46","736.48","736.5","736.52","736.54","736.56","736.58","736.6","736.62","736.64","736.66","736.68","736.7","736.72","736.74","736.76"],"Ask":[0,32,27,37,57,110,135,80,92,28,14,58,99,15,49,31,25,8,11,3,108,127,64,51,70,82,45,37,17,33,38,43,44,13,6,10],"Bid":[14,50,65,125,32,23,133,11,11,45,29,14,93,41,13,48,48,40,44,53,139,98,91,52,35,159,51,51,35,21,43,20,39,7,0,0],"symbol":"au2506","datetime":"2025-04-01 22:12:00","delta":-74.0,"close":736.3,"open":736.66,"high":736.76,"low":736.06,"volume":3720,"dj":-1,"dayma":737.1816216216,"delta累计":-1478.0} +{"price":["735.1","735.12","735.14","735.16","735.18","735.2","735.22","735.24","735.26","735.28","735.3","735.32","735.34","735.36","735.38","735.4","735.42","735.44","735.46","735.48","735.5","735.52","735.54","735.56","735.58","735.6","735.62","735.7","735.72","735.76","735.8","735.82","735.84","735.86","735.88","735.9","735.92","735.94","735.96","735.98","736.02","736.04","736.06","736.08","736.1","736.12","736.14","736.16","736.18","736.2","736.22","736.24","736.26","736.28","736.3","736.32","736.34","736.36","736.38","736.4","736.42","736.44","736.46","736.48","736.5","736.52","736.54","736.56"],"Ask":[97,75,39,37,55,86,14,7,19,69,81,98,40,16,45,97,0,61,29,0,0,83,40,97,0,98,0,47,0,38,0,0,0,74,40,34,28,16,46,29,0,0,51,60,141,54,16,43,14,0,0,57,0,11,0,43,11,47,31,22,34,50,33,61,99,75,36,30],"Bid":[55,178,42,23,22,0,74,59,7,100,25,110,36,53,105,58,32,46,15,50,123,167,37,0,64,29,30,9,92,0,57,20,30,26,115,0,13,76,267,33,75,22,50,83,92,34,10,24,16,21,62,18,23,22,16,49,0,1,53,38,37,19,0,41,38,38,24,0],"symbol":"au2506","datetime":"2025-04-01 22:15:00","delta":-530.0,"close":735.28,"open":736.36,"high":736.56,"low":735.1,"volume":6258,"dj":-1,"dayma":737.1562666667,"delta累计":-2008.0} +{"price":["735.02","735.06","735.08","735.1","735.12","735.14","735.16","735.18","735.2","735.22","735.24","735.26","735.28","735.3","735.32","735.34","735.36","735.38","735.4","735.42","735.52","735.6","735.62","735.64","735.66","735.68","735.7","735.72","735.74","735.76","735.78","735.8","735.82","735.84","735.86","735.88","735.9","735.92","735.94","735.96","735.98","736.0","736.02","736.04","736.06","736.08","736.1","736.12","736.16"],"Ask":[0,24,61,0,49,96,11,104,0,42,26,49,135,55,75,150,37,215,84,117,0,0,0,0,53,15,0,64,58,233,83,28,133,36,44,12,67,50,49,26,20,33,88,86,21,0,4,21,21],"Bid":[38,76,26,64,52,57,36,89,46,107,51,166,22,89,108,80,52,150,122,2,27,22,14,20,46,37,12,23,113,122,115,57,66,6,29,19,56,75,170,19,54,75,86,60,0,37,33,54,39],"symbol":"au2506","datetime":"2025-04-01 22:18:00","delta":-344.0,"close":735.78,"open":735.24,"high":736.16,"low":735.02,"volume":6000,"dj":-2,"dayma":737.1381578947,"delta累计":-2352.0} +{"price":["735.32","735.34","735.36","735.38","735.4","735.42","735.44","735.46","735.48","735.5","735.52","735.54","735.56","735.58","735.6","735.62","735.64","735.66","735.68","735.7","735.72","735.74","735.76","735.78","735.8","735.82","735.84"],"Ask":[0,19,30,53,86,17,112,0,51,27,52,37,43,41,128,116,88,81,68,59,26,50,18,17,8,9,0],"Bid":[16,19,29,69,56,51,36,25,47,120,59,73,38,71,119,55,95,60,64,16,40,74,58,0,74,0,5],"symbol":"au2506","datetime":"2025-04-01 22:21:00","delta":-133.0,"close":735.38,"open":735.72,"high":735.84,"low":735.32,"volume":2969,"dj":0,"dayma":737.1153246753,"delta累计":-2485.0} +{"price":["734.8","734.82","734.84","734.86","734.88","734.9","734.92","734.94","734.96","734.98","735.0","735.02","735.04","735.06","735.08","735.1","735.12","735.14","735.16","735.18","735.2","735.22","735.24","735.26","735.28","735.3","735.32","735.34","735.36","735.38","735.4","735.42","735.44","735.46","735.48","735.5","735.52","735.54","735.56","735.58"],"Ask":[0,0,69,17,89,97,19,61,75,0,0,94,21,89,71,99,58,187,65,58,50,32,101,158,22,73,49,63,93,47,38,73,51,46,86,23,41,6,8,7],"Bid":[82,27,33,20,81,174,0,0,0,283,30,109,3,25,93,26,89,112,131,27,149,166,48,137,101,75,28,156,126,2,21,40,15,54,30,52,45,0,0,0],"symbol":"au2506","datetime":"2025-04-01 22:24:00","delta":-354.0,"close":735.26,"open":735.36,"high":735.58,"low":734.8,"volume":5337,"dj":0,"dayma":737.0915384615,"delta累计":-2839.0} +{"price":["735.22","735.24","735.26","735.28","735.3","735.32","735.34","735.38","735.4","735.42","735.44","735.46","735.48","735.5","735.52","735.54","735.56","735.58","735.6","735.62","735.64","735.66","735.68","735.7","735.72","735.74","735.76","735.78","735.8","735.82","735.84","735.86","735.88","735.9","735.92","735.94","735.96","735.98","736.0","736.02"],"Ask":[30,5,7,19,11,12,41,0,27,44,16,0,95,55,0,38,18,21,90,0,15,25,118,128,88,20,24,17,90,77,46,140,217,136,115,46,6,10,65,25],"Bid":[0,7,0,0,1,23,0,77,0,10,73,43,55,13,75,0,0,0,30,22,2,20,101,128,51,0,2,82,17,73,149,158,65,55,79,64,26,13,27,19],"symbol":"au2506","datetime":"2025-04-01 22:27:00","delta":377.0,"close":735.84,"open":735.24,"high":736.02,"low":735.22,"volume":3770,"dj":2,"dayma":737.0756962025,"delta累计":-2462.0} +{"price":["735.46","735.48","735.5","735.52","735.54","735.56","735.58","735.6","735.62","735.64","735.66","735.68","735.7","735.72","735.74","735.76","735.78","735.8","735.82","735.84","735.86","735.88","735.9","735.92","735.96","735.98","736.0","736.02","736.04","736.06","736.08","736.1","736.12","736.14","736.16","736.18"],"Ask":[0,26,34,76,0,11,2,46,73,49,50,44,54,28,57,40,31,21,0,25,48,81,7,15,48,26,24,18,76,17,9,123,73,83,31,100],"Bid":[23,14,42,44,13,7,0,115,27,80,44,44,30,26,106,77,74,30,36,27,89,8,0,0,31,34,51,91,0,12,58,53,78,12,3,0],"symbol":"au2506","datetime":"2025-04-01 22:30:00","delta":67.0,"close":735.62,"open":735.86,"high":736.18,"low":735.46,"volume":2990,"dj":0,"dayma":737.0575,"delta累计":-2395.0} +{"price":["735.04","735.08","735.1","735.12","735.14","735.16","735.18","735.2","735.22","735.24","735.26","735.28","735.3","735.32","735.34","735.36","735.38","735.4","735.42","735.44","735.46","735.48","735.5","735.52","735.54","735.56","735.58","735.6","735.62"],"Ask":[0,0,42,0,0,27,56,66,18,112,21,56,65,69,40,86,108,28,14,96,171,46,90,134,74,19,2,44,11],"Bid":[20,15,29,36,10,27,41,20,142,33,50,103,72,35,134,65,21,67,123,165,144,117,104,86,42,92,11,25,21],"symbol":"au2506","datetime":"2025-04-01 22:33:00","delta":-355.0,"close":735.3,"open":735.54,"high":735.62,"low":735.04,"volume":3679,"dj":0,"dayma":737.0358024691,"delta累计":-2750.0} +{"price":["735.06","735.08","735.1","735.12","735.14","735.16","735.18","735.2","735.22","735.24","735.26","735.28","735.3","735.32","735.34","735.36","735.38","735.4","735.42","735.44","735.46","735.48","735.5","735.52","735.54","735.56","735.58","735.6","735.62","735.64","735.66","735.68","735.7"],"Ask":[0,33,54,48,29,50,39,28,13,53,63,43,14,17,11,33,9,19,32,14,55,115,42,6,73,29,32,91,153,5,21,25,27],"Bid":[7,55,20,26,49,8,31,45,18,82,57,34,0,6,10,15,0,24,43,52,172,227,91,33,35,28,119,52,44,8,25,11,0],"symbol":"au2506","datetime":"2025-04-01 22:36:00","delta":-151.0,"close":735.42,"open":735.26,"high":735.7,"low":735.06,"volume":2937,"dj":0,"dayma":737.016097561,"delta累计":-2901.0} +{"price":["735.42","735.44","735.46","735.48","735.5","735.52","735.54","735.56","735.58","735.6","735.62","735.64","735.66","735.68","735.7","735.72","735.74","735.76","735.78","735.8","735.82","735.84","735.86","735.88","735.9","735.92","735.94","735.96","735.98","736.0","736.02"],"Ask":[0,6,34,38,9,23,3,49,43,21,64,9,59,81,79,72,63,43,107,143,12,0,29,85,28,17,47,95,73,23,29],"Bid":[26,9,46,24,27,32,21,66,19,36,40,37,37,138,118,88,31,14,56,27,15,20,0,8,0,7,46,137,73,8,27],"symbol":"au2506","datetime":"2025-04-01 22:39:00","delta":151.0,"close":735.94,"open":735.42,"high":736.02,"low":735.42,"volume":2931,"dj":2,"dayma":737.0031325301,"delta累计":-2750.0} +{"price":["735.66","735.7","735.72","735.74","735.76","735.78","735.8","735.82","735.84","735.86","735.88","735.9","735.92","735.94","735.96","735.98","736.0","736.02","736.04","736.06","736.08"],"Ask":[0,0,21,38,23,27,53,21,10,25,46,69,52,103,119,146,214,89,87,59,31],"Bid":[6,53,8,32,10,24,0,40,2,10,35,103,98,191,121,90,88,77,19,11,14],"symbol":"au2506","datetime":"2025-04-01 22:42:00","delta":201.0,"close":736.0,"open":735.96,"high":736.08,"low":735.66,"volume":2445,"dj":0,"dayma":736.9911904762,"delta累计":-2549.0} +{"price":["735.62","735.66","735.68","735.7","735.72","735.74","735.76","735.78","735.8","735.82","735.84","735.86","735.88","735.9","735.92","735.94","735.96","735.98","736.0","736.02","736.04","736.06","736.08","736.1","736.12","736.14","736.16","736.18","736.2","736.22","736.24","736.26","736.28","736.3"],"Ask":[0,13,1,0,0,0,9,26,40,0,13,0,0,38,4,21,24,68,30,43,44,45,41,107,27,36,49,23,83,45,70,64,156,32],"Bid":[24,20,13,7,15,19,81,11,41,3,0,24,14,68,66,21,74,137,21,97,28,77,13,80,71,42,30,77,81,59,105,147,45,0],"symbol":"au2506","datetime":"2025-04-01 22:45:00","delta":-459.0,"close":735.68,"open":736.0,"high":736.3,"low":735.62,"volume":3014,"dj":-2,"dayma":736.9757647059,"delta累计":-3008.0} +{"price":["735.54","735.56","735.58","735.6","735.62","735.64","735.66","735.68","735.7","735.72","735.74","735.76","735.78","735.8","735.82","735.84","735.86","735.88","735.9","735.92","735.94","735.96","735.98","736.0","736.02","736.04"],"Ask":[0,41,111,67,67,32,107,101,29,69,49,13,15,27,80,53,37,44,33,15,11,55,2,28,45,17],"Bid":[63,67,124,63,42,47,76,44,25,4,14,16,9,54,30,62,37,5,25,6,36,17,65,9,31,3],"symbol":"au2506","datetime":"2025-04-01 22:48:00","delta":174.0,"close":735.92,"open":735.66,"high":736.04,"low":735.54,"volume":2298,"dj":0,"dayma":736.9634883721,"delta累计":-2834.0} +{"price":["735.72","735.76","735.78","735.8","735.82","735.84","735.86","735.88","735.9","735.92","735.94","735.96","735.98","736.0","736.02","736.04","736.06","736.08","736.1","736.14","736.16","736.18","736.2","736.22","736.24","736.26","736.28","736.32","736.34","736.36","736.42","736.44","736.46","736.48","736.5","736.52","736.54","736.56","736.58"],"Ask":[0,0,3,30,35,9,46,1,17,17,32,24,15,44,31,36,42,63,16,15,10,71,52,87,75,50,59,36,12,73,48,48,45,83,181,84,104,34,18],"Bid":[22,28,21,5,4,62,16,13,25,38,39,16,20,10,54,53,91,7,0,0,0,88,48,18,67,57,29,0,0,34,0,8,59,91,42,38,85,41,51],"symbol":"au2506","datetime":"2025-04-01 22:51:00","delta":366.0,"close":736.5,"open":735.94,"high":736.6,"low":735.72,"volume":3116,"dj":1,"dayma":736.9581609195,"delta累计":-2468.0} +{"price":["735.96","735.98","736.0","736.02","736.04","736.06","736.08","736.1","736.12","736.14","736.16","736.18","736.2","736.22","736.24","736.26","736.28","736.3","736.32","736.34","736.36","736.4","736.42","736.44","736.46","736.48","736.5"],"Ask":[14,11,41,62,71,93,54,81,83,118,22,83,32,43,33,27,17,0,68,31,14,7,53,0,0,0,14],"Bid":[34,73,94,97,137,128,93,78,30,70,141,28,99,0,42,39,25,22,27,15,24,54,8,5,5,9,0],"symbol":"au2506","datetime":"2025-04-01 22:54:00","delta":-305.0,"close":736.04,"open":736.5,"high":736.5,"low":735.96,"volume":2710,"dj":-1,"dayma":736.9477272727,"delta累计":-2773.0} +{"price":["735.9","735.92","735.94","735.96","735.98","736.0","736.02","736.04","736.06","736.08","736.12","736.16","736.18","736.2","736.22","736.24","736.26","736.28","736.3","736.32","736.34","736.36","736.38","736.4","736.42","736.44","736.46","736.48"],"Ask":[0,21,24,33,30,5,48,34,48,39,19,23,0,23,14,17,88,64,176,184,132,46,76,27,108,43,80,50],"Bid":[6,5,0,39,69,200,43,158,51,0,0,3,33,31,23,20,77,108,219,136,79,103,29,48,13,0,0,0],"symbol":"au2506","datetime":"2025-04-01 22:57:00","delta":-41.0,"close":736.3,"open":736.06,"high":736.48,"low":735.9,"volume":3178,"dj":2,"dayma":736.9404494382,"delta累计":-2814.0} +{"price":["736.28","736.3","736.32","736.36","736.38","736.4","736.42","736.44","736.46","736.48","736.5","736.52","736.54","736.56","736.58","736.6","736.62","736.64","736.66","736.68","736.7"],"Ask":[0,0,7,49,23,99,46,54,92,107,180,133,168,96,140,105,98,30,28,64,33],"Bid":[8,3,16,16,69,12,35,57,255,128,152,83,114,75,48,15,51,26,13,7,50],"symbol":"au2506","datetime":"2025-04-01 23:00:00","delta":319.0,"close":736.46,"open":736.3,"high":736.7,"low":736.28,"volume":2993,"dj":0,"dayma":736.9351111111,"delta累计":-2495.0} +{"price":["736.28","736.3","736.32","736.34","736.36","736.38","736.4","736.42","736.44","736.46","736.48","736.5","736.52","736.54","736.56","736.58","736.6","736.62","736.64","736.66"],"Ask":[2,41,31,2,17,72,9,14,13,13,52,38,73,57,31,33,98,46,30,32],"Bid":[63,51,19,8,30,37,6,5,17,57,28,29,49,51,70,39,82,27,0,0],"symbol":"au2506","datetime":"2025-04-01 23:03:00","delta":36.0,"close":736.5,"open":736.48,"high":736.66,"low":736.28,"volume":1470,"dj":0,"dayma":736.9303296703,"delta累计":-2459.0} +{"price":["736.5","736.52","736.56","736.58","736.6","736.62","736.64","736.66","736.68","736.7","736.72","736.74","736.76","736.78","736.8","736.82","736.84","736.86","736.88","736.9","736.92","736.94"],"Ask":[5,1,7,106,3,44,22,10,19,11,7,9,21,55,119,120,139,258,102,128,55,27],"Bid":[1,7,6,0,4,9,9,0,0,26,9,21,32,128,93,123,130,127,111,58,0,0],"symbol":"au2506","datetime":"2025-04-01 23:06:00","delta":374.0,"close":736.94,"open":736.5,"high":736.94,"low":736.5,"volume":2291,"dj":1,"dayma":736.9304347826,"delta累计":-2085.0} +{"price":["736.82","736.84","736.86","736.88","736.9","736.92","736.94","736.96","736.98","737.0","737.02","737.04","737.06","737.08","737.1","737.12","737.14"],"Ask":[0,6,0,16,57,28,71,43,43,101,100,48,47,99,123,41,58],"Bid":[7,20,53,19,82,76,71,193,23,142,38,39,93,69,96,13,3],"symbol":"au2506","datetime":"2025-04-01 23:09:00","delta":-156.0,"close":736.92,"open":736.96,"high":737.14,"low":736.82,"volume":2028,"dj":0,"dayma":736.9303225806,"delta累计":-2241.0} +{"price":["736.48","736.5","736.52","736.54","736.56","736.58","736.6","736.62","736.64","736.66","736.68","736.7","736.72","736.74","736.76","736.78","736.8","736.82","736.84","736.86","736.88","736.9","736.92","736.94","736.96"],"Ask":[0,31,142,47,36,23,38,60,59,119,3,24,0,0,0,11,29,106,35,11,14,2,13,3,10],"Bid":[34,63,99,116,77,49,39,162,41,43,63,21,12,12,74,14,93,23,41,34,12,15,17,0,11],"symbol":"au2506","datetime":"2025-04-01 23:12:00","delta":-349.0,"close":736.52,"open":736.9,"high":736.96,"low":736.48,"volume":2131,"dj":-2,"dayma":736.9259574468,"delta累计":-2590.0} +{"price":["736.42","736.44","736.46","736.48","736.5","736.52","736.54","736.56","736.58","736.6","736.62","736.64","736.66","736.68","736.7","736.72","736.74","736.76","736.78","736.8","736.82","736.84","736.86","736.88"],"Ask":[0,0,4,44,23,51,2,4,9,10,26,34,71,68,33,26,9,44,43,75,17,8,7,17],"Bid":[33,4,6,13,39,20,5,22,0,18,12,60,30,42,15,20,34,21,52,51,4,39,9,0],"symbol":"au2506","datetime":"2025-04-01 23:15:00","delta":76.0,"close":736.72,"open":736.5,"high":736.88,"low":736.42,"volume":1240,"dj":0,"dayma":736.9237894737,"delta累计":-2514.0} +{"price":["736.12","736.14","736.16","736.2","736.22","736.24","736.26","736.28","736.3","736.32","736.34","736.36","736.38","736.4","736.42","736.46","736.54","736.56","736.58","736.6","736.62","736.64","736.66","736.68","736.7","736.72","736.74","736.76","736.78","736.8","736.82","736.84","736.86"],"Ask":[0,17,0,0,30,24,61,59,3,8,30,35,55,0,6,0,0,0,14,20,15,49,70,46,36,51,4,9,9,7,4,25,6],"Bid":[13,44,23,29,62,67,31,42,80,32,51,52,10,34,0,40,2,2,1,59,58,47,25,67,63,38,18,0,0,0,13,4,0],"symbol":"au2506","datetime":"2025-04-01 23:18:00","delta":-314.0,"close":736.22,"open":736.74,"high":736.86,"low":736.12,"volume":1831,"dj":1,"dayma":736.9164583333,"delta累计":-2828.0} +{"price":["735.92","735.96","735.98","736.0","736.02","736.04","736.06","736.08","736.1","736.12","736.14","736.16","736.18","736.2","736.22","736.24","736.26","736.28","736.3","736.32","736.34","736.36","736.38","736.4","736.42"],"Ask":[47,25,0,65,74,12,17,13,3,58,119,49,78,9,16,9,18,21,59,37,52,25,31,13,10],"Bid":[43,18,66,47,77,3,49,45,55,57,66,36,44,29,26,17,19,52,44,60,16,34,43,6,9],"symbol":"au2506","datetime":"2025-04-01 23:21:00","delta":-101.0,"close":736.06,"open":736.24,"high":736.42,"low":735.92,"volume":2015,"dj":0,"dayma":736.907628866,"delta累计":-2929.0} +{"price":["736.0","736.02","736.04","736.06","736.08","736.1","736.12","736.14","736.16","736.18","736.2","736.22","736.24","736.26","736.28","736.3","736.32","736.34","736.36","736.38","736.4"],"Ask":[0,0,0,26,9,3,38,44,65,53,50,78,24,46,42,43,40,64,16,13,17],"Bid":[28,42,4,32,3,64,25,47,20,126,32,25,39,20,35,16,48,13,7,10,17],"symbol":"au2506","datetime":"2025-04-01 23:24:00","delta":18.0,"close":736.28,"open":736.06,"high":736.4,"low":736.0,"volume":1414,"dj":0,"dayma":736.9012244898,"delta累计":-2911.0} +{"price":["735.74","735.76","735.78","735.8","735.82","735.84","735.86","735.88","735.9","735.92","735.94","735.96","735.98","736.0","736.02","736.04","736.1","736.14","736.16","736.18","736.2","736.22","736.24","736.26","736.28","736.3","736.32"],"Ask":[16,0,0,13,70,70,8,40,137,66,23,42,29,46,29,50,0,0,0,15,6,40,28,22,22,12,7],"Bid":[7,13,4,48,78,34,43,66,126,65,69,55,17,79,21,17,37,6,1,19,18,26,28,17,8,17,8],"symbol":"au2506","datetime":"2025-04-01 23:27:00","delta":-136.0,"close":735.8,"open":736.3,"high":736.32,"low":735.74,"volume":1919,"dj":-1,"dayma":736.8901010101,"delta累计":-3047.0} +{"price":["735.72","735.74","735.76","735.78","735.8","735.82","735.84","735.86","735.88","735.9","735.92","735.94","735.96"],"Ask":[3,48,20,58,43,60,46,97,64,47,51,10,16],"Bid":[10,54,54,44,92,131,99,34,93,43,55,9,0],"symbol":"au2506","datetime":"2025-04-01 23:30:00","delta":-155.0,"close":735.86,"open":735.78,"high":735.96,"low":735.72,"volume":1356,"dj":0,"dayma":736.8798,"delta累计":-3202.0} +{"price":["735.56","735.58","735.6","735.62","735.64","735.66","735.68","735.7","735.72","735.74","735.76","735.78","735.8","735.82","735.84","735.86","735.88","735.9","735.92","735.94","735.96","735.98","736.0","736.02","736.04"],"Ask":[0,47,19,39,10,43,23,61,36,41,41,20,17,46,19,33,19,16,39,73,52,65,36,0,20],"Bid":[6,4,53,33,9,53,58,57,57,29,47,0,50,13,63,12,36,35,52,44,36,0,26,6,0],"symbol":"au2506","datetime":"2025-04-01 23:33:00","delta":36.0,"close":736.02,"open":735.84,"high":736.04,"low":735.56,"volume":1704,"dj":0,"dayma":736.8712871287,"delta累计":-3166.0} +{"price":["735.72","735.76","735.78","735.8","735.82","735.84","735.86","735.88","735.9","735.92","735.94","735.96","735.98","736.0","736.02","736.04"],"Ask":[0,9,26,14,3,12,20,63,54,52,32,33,40,87,20,33],"Bid":[2,13,0,2,16,12,4,99,57,66,20,49,46,52,15,4],"symbol":"au2506","datetime":"2025-04-01 23:36:00","delta":41.0,"close":736.0,"open":736.04,"high":736.04,"low":735.72,"volume":1031,"dj":0,"dayma":736.862745098,"delta累计":-3125.0} +{"price":["735.6","735.62","735.66","735.68","735.7","735.72","735.74","735.76","735.78","735.8","735.82","735.84","735.86","735.88","735.9","735.92","735.94","735.96","735.98","736.0","736.02","736.04"],"Ask":[0,0,22,15,0,16,6,4,12,36,13,12,18,15,14,33,58,37,30,19,5,2],"Bid":[43,5,0,0,37,0,7,17,15,35,36,32,45,6,23,92,37,17,24,0,4,0],"symbol":"au2506","datetime":"2025-04-01 23:39:00","delta":-108.0,"close":735.74,"open":736.0,"high":736.04,"low":735.6,"volume":908,"dj":0,"dayma":736.8518446602,"delta累计":-3233.0} +{"price":["735.42","735.44","735.46","735.48","735.5","735.52","735.54","735.56","735.58","735.6","735.62","735.64","735.66","735.68","735.7","735.72","735.74"],"Ask":[0,19,16,9,20,0,66,70,118,71,68,10,76,49,32,42,25],"Bid":[12,132,9,20,100,42,53,90,79,123,44,64,60,42,29,5,13],"symbol":"au2506","datetime":"2025-04-01 23:42:00","delta":-226.0,"close":735.42,"open":735.7,"high":735.74,"low":735.42,"volume":1784,"dj":0,"dayma":736.8380769231,"delta累计":-3459.0} +{"price":["734.52","734.54","734.56","734.58","734.6","734.62","734.64","734.66","734.68","734.7","734.72","734.74","734.76","734.78","734.8","734.82","734.84","734.86","734.88","734.9","734.92","734.94","734.96","734.98","735.0","735.02","735.04","735.06","735.08","735.1","735.12","735.14","735.16","735.18","735.2","735.22","735.26","735.28","735.32","735.34","735.36","735.38","735.4","735.42","735.44","735.46","735.48","735.5"],"Ask":[0,0,132,141,73,16,233,92,5,18,35,39,52,12,10,19,37,119,66,0,148,113,121,64,35,69,129,18,0,16,26,0,0,16,0,0,0,0,0,0,0,0,0,8,30,31,6,56],"Bid":[66,124,91,95,80,78,0,32,68,31,0,148,11,0,0,33,72,68,246,57,107,182,72,290,0,38,90,48,52,0,61,36,10,38,56,12,5,11,3,22,6,20,32,36,34,18,31,15],"symbol":"au2506","datetime":"2025-04-01 23:45:00","delta":-640.0,"close":734.94,"open":735.42,"high":735.5,"low":734.52,"volume":5014,"dj":-9,"dayma":736.82,"delta累计":-4099.0} +{"price":["734.8","734.82","734.84","734.86","734.88","734.9","734.92","734.94","734.96","734.98","735.0","735.02","735.04","735.06","735.08","735.1","735.12","735.14","735.16","735.18","735.2","735.22","735.24","735.26","735.28","735.3","735.32","735.34","735.36"],"Ask":[19,12,31,10,136,46,28,39,15,17,88,74,147,48,57,45,25,64,53,20,100,35,75,46,22,39,14,16,10],"Bid":[4,10,72,27,12,66,10,7,16,43,110,154,77,62,51,16,24,96,50,42,104,53,34,108,33,49,0,39,0],"symbol":"au2506","datetime":"2025-04-01 23:48:00","delta":-38.0,"close":735.22,"open":734.92,"high":735.36,"low":734.8,"volume":3068,"dj":0,"dayma":736.8049056604,"delta累计":-4137.0} +{"price":["734.54","734.56","734.58","734.6","734.62","734.68","734.7","734.72","734.74","734.76","734.78","734.8","734.82","734.84","734.86","734.88","734.9","734.92","734.94","734.96","734.98","735.0","735.02","735.04","735.06","735.08","735.1","735.12","735.16","735.18","735.22"],"Ask":[0,0,25,16,23,7,0,0,0,0,48,74,43,31,17,35,6,16,24,60,54,43,23,54,61,58,34,20,6,0,2],"Bid":[8,46,0,53,19,0,34,49,6,8,15,80,40,45,41,14,44,46,26,73,44,75,36,65,64,52,7,29,0,15,9],"symbol":"au2506","datetime":"2025-04-01 23:51:00","delta":-263.0,"close":734.68,"open":735.22,"high":735.22,"low":734.54,"volume":1964,"dj":-1,"dayma":736.785046729,"delta累计":-4400.0} +{"price":["733.7","733.72","733.74","733.76","733.78","733.8","733.82","733.84","733.86","733.88","733.9","733.92","733.94","733.96","733.98","734.0","734.02","734.04","734.1","734.12","734.16","734.22","734.24","734.26","734.28","734.32","734.36","734.42","734.44","734.46","734.5","734.52","734.54","734.56","734.58","734.6","734.62","734.64","734.66","734.68","734.7","734.72","734.74","734.76","734.78","734.8","734.82","734.84","734.86","734.88"],"Ask":[60,65,18,134,68,79,39,164,42,10,3,111,39,47,32,44,0,0,93,0,0,68,7,63,25,56,0,0,19,0,0,121,10,11,84,22,47,4,16,48,36,36,33,79,130,58,13,10,10,1],"Bid":[43,90,90,176,45,26,103,126,13,0,27,147,186,62,38,63,102,49,23,126,31,0,92,0,6,78,71,22,0,10,185,29,0,32,56,0,9,36,6,90,43,36,56,75,32,24,0,0,8,0],"symbol":"au2506","datetime":"2025-04-01 23:54:00","delta":-507.0,"close":733.78,"open":734.64,"high":734.88,"low":733.7,"volume":5292,"dj":0,"dayma":736.7572222222,"delta累计":-4907.0} +{"price":["733.72","733.74","733.76","733.78","733.8","733.82","733.84","733.86","733.88","733.9","733.92","733.94","733.96","733.98","734.0","734.02","734.04","734.06","734.08","734.1","734.12","734.14","734.16","734.18","734.2","734.22","734.24","734.26"],"Ask":[0,0,90,21,14,40,23,28,0,45,69,66,58,125,210,31,78,138,119,40,48,62,63,16,43,71,66,5],"Bid":[24,27,67,68,10,0,46,7,76,12,60,81,6,113,104,51,157,159,142,86,69,30,70,23,34,5,8,0],"symbol":"au2506","datetime":"2025-04-01 23:57:00","delta":34.0,"close":734.0,"open":733.78,"high":734.26,"low":733.72,"volume":3406,"dj":0,"dayma":736.7319266055,"delta累计":-4873.0} +{"price":["733.08","733.1","733.14","733.16","733.2","733.22","733.24","733.26","733.28","733.3","733.32","733.34","733.38","733.4","733.42","733.44","733.46","733.48","733.5","733.52","733.54","733.56","733.58","733.6","733.62","733.64","733.66","733.68","733.7","733.72","733.74","733.76","733.78","733.8","733.82","733.84","733.86","733.88","733.9","733.92","733.94","733.96","734.0"],"Ask":[0,38,29,55,16,0,0,5,5,80,6,0,0,52,55,47,35,0,0,14,104,127,84,69,42,121,71,24,56,68,68,19,16,36,27,66,23,35,36,98,0,12,10],"Bid":[11,120,82,49,15,10,10,74,108,13,0,7,153,83,8,65,0,46,68,39,225,64,67,59,20,80,59,94,27,78,135,16,76,47,31,75,36,102,8,6,9,10,0],"symbol":"au2506","datetime":"2025-04-02 00:00:00","delta":-636.0,"close":733.16,"open":734.0,"high":734.0,"low":733.08,"volume":4529,"dj":-1,"dayma":736.6994545455,"delta累计":-5509.0} +{"price":["732.76","732.8","732.82","732.84","732.86","732.88","732.9","732.92","732.94","732.96","732.98","733.0","733.02","733.04","733.06","733.08","733.1","733.12","733.14","733.16","733.18","733.2","733.22","733.24","733.26","733.28","733.3","733.32","733.34","733.38","733.42","733.44","733.46","733.48","733.5","733.52","733.54","733.56","733.58","733.6","733.62","733.64","733.66","733.68","733.7","733.72","733.74","733.76","733.78","733.8","733.82","733.84","733.96"],"Ask":[0,85,150,7,0,104,9,52,13,11,12,98,135,126,25,103,49,204,81,81,110,66,113,74,10,157,92,31,48,25,19,4,29,0,0,43,110,35,78,12,5,0,23,8,23,84,94,51,20,13,10,11,82],"Bid":[33,43,7,0,58,19,47,140,10,8,42,300,76,66,67,14,186,215,176,27,11,48,41,24,92,94,52,0,41,31,66,0,4,19,32,33,63,34,36,6,7,23,34,2,68,37,52,73,45,71,21,8,0],"symbol":"au2506","datetime":"2025-04-02 00:03:00","delta":123.0,"close":733.64,"open":733.14,"high":733.96,"low":732.76,"volume":6245,"dj":-1,"dayma":736.6718918919,"delta累计":-5386.0} +{"price":["732.82","732.86","732.88","732.9","732.92","732.94","732.96","732.98","733.0","733.02","733.04","733.06","733.08","733.1","733.12","733.14","733.16","733.18","733.2","733.22","733.24","733.26","733.28","733.3","733.32","733.34","733.36","733.38","733.4","733.42","733.44","733.48","733.6","733.62","733.64","733.66","733.68","733.7","733.72","733.76"],"Ask":[0,24,67,23,79,42,88,138,148,31,78,22,28,28,0,14,29,55,37,68,81,138,156,101,33,50,56,13,4,30,19,7,0,0,0,4,0,23,6,13],"Bid":[11,0,42,93,39,22,27,102,88,13,44,40,7,23,13,3,31,19,3,87,141,65,156,64,49,61,46,42,7,25,25,21,15,6,8,14,17,8,0,0],"symbol":"au2506","datetime":"2025-04-02 00:06:00","delta":256.0,"close":733.34,"open":733.66,"high":733.76,"low":732.82,"volume":3561,"dj":-2,"dayma":736.6421428571,"delta累计":-5130.0} +{"price":["732.38","732.4","732.42","732.44","732.46","732.48","732.5","732.52","732.54","732.56","732.58","732.6","732.62","732.64","732.66","732.68","732.7","732.72","732.74","732.76","732.78","732.8","732.82","732.84","732.86","732.88","732.9","732.92","732.94","732.96","732.98","733.0","733.02","733.04","733.1","733.12","733.14","733.16","733.18","733.2","733.22","733.28","733.3","733.32","733.34","733.36","733.38"],"Ask":[0,0,31,35,41,73,94,41,69,53,129,58,111,62,57,26,111,27,30,31,52,67,121,33,12,76,79,70,37,45,83,0,30,9,0,7,0,23,5,29,0,4,7,14,7,11,3],"Bid":[18,116,5,120,33,72,160,36,86,125,128,57,172,76,3,42,56,42,56,65,86,72,61,63,102,66,98,104,15,7,0,6,19,12,11,29,20,1,9,35,35,17,31,4,6,3,0],"symbol":"au2506","datetime":"2025-04-02 00:09:00","delta":-477.0,"close":732.74,"open":733.34,"high":733.38,"low":732.38,"volume":5020,"dj":0,"dayma":736.6076106195,"delta累计":-5607.0} +{"price":["732.46","732.48","732.5","732.52","732.54","732.56","732.58","732.6","732.62","732.64","732.66","732.68","732.7","732.72","732.74","732.76","732.78","732.8","732.82","732.84","732.86","732.88","732.9","732.92","732.94","732.96"],"Ask":[0,24,70,12,36,60,54,47,51,97,76,84,91,151,58,30,21,78,83,48,87,9,9,7,0,10],"Bid":[78,49,11,60,43,84,38,65,69,49,100,65,92,105,79,126,46,30,36,63,68,31,0,10,10,0],"symbol":"au2506","datetime":"2025-04-02 00:12:00","delta":-114.0,"close":732.74,"open":732.8,"high":732.96,"low":732.46,"volume":2958,"dj":0,"dayma":736.5736842105,"delta累计":-5721.0} +{"price":["732.14","732.18","732.2","732.22","732.24","732.26","732.28","732.3","732.32","732.34","732.36","732.38","732.4","732.42","732.44","732.46","732.48","732.5","732.52","732.54","732.56","732.58","732.6","732.62","732.64","732.66","732.68"],"Ask":[0,17,67,42,27,91,14,172,135,32,50,40,11,20,18,52,84,38,104,30,55,90,27,120,31,29,23],"Bid":[12,26,124,67,79,36,66,116,49,2,27,48,16,24,79,30,138,90,79,79,74,45,73,75,32,3,17],"symbol":"au2506","datetime":"2025-04-02 00:15:00","delta":-87.0,"close":732.2,"open":732.68,"high":732.68,"low":732.14,"volume":3178,"dj":0,"dayma":736.5356521739,"delta累计":-5808.0} +{"price":["731.5","731.52","731.54","731.56","731.58","731.6","731.62","731.64","731.66","731.68","731.7","731.72","731.74","731.76","731.78","731.8","731.86","731.88","731.9","731.92","731.96","731.98","732.02","732.04","732.06","732.08","732.12","732.14","732.16","732.18","732.2","732.22","732.24","732.26","732.28","732.3","732.32","732.34","732.36","732.38","732.4","732.42","732.44","732.46","732.48","732.5","732.52","732.54","732.56","732.58","732.6"],"Ask":[81,0,0,0,22,35,116,23,51,139,78,34,52,118,47,74,41,0,17,41,38,0,144,83,0,0,44,32,0,33,77,53,183,104,106,55,49,30,34,105,89,4,0,8,9,0,8,10,68,37,20],"Bid":[69,73,36,14,41,58,21,93,36,57,13,105,0,30,25,107,0,200,53,0,0,17,0,12,25,17,0,63,31,88,94,147,223,34,120,55,86,2,45,7,27,0,59,1,9,91,7,19,0,0,6],"symbol":"au2506","datetime":"2025-04-02 00:18:00","delta":76.0,"close":731.64,"open":732.2,"high":732.6,"low":731.5,"volume":5358,"dj":0,"dayma":736.4934482759,"delta累计":-5732.0} +{"price":["731.2","731.22","731.24","731.26","731.28","731.3","731.32","731.34","731.36","731.38","731.4","731.42","731.44","731.46","731.48","731.5","731.52","731.54","731.56","731.58","731.6","731.62","731.64","731.66","731.68","731.7","731.72","731.74","731.76","731.78","731.8","731.82","731.84","731.86","731.88","731.9","731.92","731.94","731.96","731.98","732.0","732.02","732.04","732.06","732.08","732.1","732.12","732.14","732.16","732.2","732.22","732.24","732.26","732.28","732.3","732.34","732.36","732.38","732.4","732.44"],"Ask":[0,0,0,159,94,0,29,52,22,11,150,46,44,38,69,134,17,0,72,27,53,34,10,13,19,26,38,58,68,163,88,34,87,105,114,25,49,9,18,7,24,0,127,0,43,42,16,46,17,24,31,51,0,48,32,19,6,0,16,13],"Bid":[36,46,65,0,50,77,37,59,35,131,80,34,44,126,106,52,0,43,0,49,0,0,53,36,25,24,110,46,198,79,29,67,116,87,68,22,7,0,9,0,72,56,5,20,26,0,28,10,27,0,0,33,10,0,7,16,5,6,0,0],"symbol":"au2506","datetime":"2025-04-02 00:21:00","delta":170.0,"close":732.44,"open":731.64,"high":732.44,"low":731.2,"volume":5444,"dj":0,"dayma":736.4588034188,"delta累计":-5562.0} +{"price":["732.32","732.34","732.36","732.38","732.4","732.42","732.44","732.46","732.48","732.5","732.52","732.54","732.56","732.58","732.6","732.62","732.64","732.66","732.68","732.7","732.72","732.74","732.76","732.78","732.8","732.82","732.84","732.86","732.88"],"Ask":[33,0,37,0,0,4,58,28,33,76,108,108,29,28,16,17,103,38,6,64,124,223,110,74,141,53,44,26,15],"Bid":[8,20,10,25,41,42,144,29,35,65,40,42,103,39,39,39,107,85,59,226,167,42,91,88,98,58,67,0,0],"symbol":"au2506","datetime":"2025-04-02 00:24:00","delta":-213.0,"close":732.48,"open":732.44,"high":732.88,"low":732.32,"volume":3805,"dj":-1,"dayma":736.4250847458,"delta累计":-5775.0} +{"price":["732.52","732.54","732.56","732.58","732.6","732.62","732.64","732.66","732.68","732.7","732.72","732.74","732.76","732.78","732.8","732.82","732.84","732.86","732.88","732.9","732.92","732.94","732.96"],"Ask":[9,2,7,16,11,24,94,22,39,99,172,57,61,146,75,74,56,38,78,126,20,51,41],"Bid":[0,7,13,19,16,6,48,81,48,82,96,92,89,73,84,83,52,61,42,104,26,0,0],"symbol":"au2506","datetime":"2025-04-02 00:27:00","delta":196.0,"close":732.96,"open":732.52,"high":732.96,"low":732.5,"volume":2580,"dj":0,"dayma":736.3959663866,"delta累计":-5579.0} +{"price":["732.9","732.92","732.94","732.96","732.98","733.0","733.02","733.04","733.06","733.08","733.1","733.12","733.14","733.16","733.18","733.2","733.22","733.24","733.26","733.28","733.3","733.32","733.34","733.36","733.38","733.4","733.42","733.44","733.46","733.48","733.5","733.52"],"Ask":[0,5,9,34,19,28,0,0,30,40,192,110,32,86,28,13,50,40,65,57,62,51,80,94,69,48,140,52,25,33,20,24],"Bid":[12,0,0,11,0,0,44,17,45,56,70,65,16,26,22,51,30,29,19,63,41,150,85,94,68,66,76,41,0,41,19,17],"symbol":"au2506","datetime":"2025-04-02 00:30:00","delta":262.0,"close":733.34,"open":732.96,"high":733.52,"low":732.9,"volume":3046,"dj":0,"dayma":736.3705,"delta累计":-5317.0} +{"price":["732.88","732.9","732.92","732.94","732.96","732.98","733.0","733.02","733.04","733.06","733.08","733.1","733.12","733.14","733.16","733.18","733.2","733.22","733.24","733.26","733.28","733.3","733.32","733.34","733.36","733.38","733.4","733.42","733.44","733.46","733.48","733.5","733.52"],"Ask":[8,27,55,57,13,18,19,19,92,29,26,44,18,46,21,24,41,56,63,22,19,81,2,16,85,73,49,13,0,17,0,0,19],"Bid":[0,27,29,37,0,52,54,78,154,87,35,74,57,38,27,53,57,53,49,64,56,9,32,7,93,34,66,18,15,18,26,5,9],"symbol":"au2506","datetime":"2025-04-02 00:33:00","delta":-341.0,"close":733.36,"open":733.3,"high":733.52,"low":732.88,"volume":2663,"dj":0,"dayma":736.3456198347,"delta累计":-5658.0} +{"price":["732.82","732.84","732.86","732.88","732.9","732.92","732.94","732.96","732.98","733.0","733.02","733.04","733.06","733.08","733.1","733.12","733.14","733.16","733.18","733.2","733.22","733.24","733.26","733.28","733.3","733.32","733.34","733.36","733.38","733.4","733.42"],"Ask":[73,29,86,49,56,16,27,53,26,51,95,27,62,96,24,24,8,24,65,0,3,0,0,8,20,12,5,15,64,81,64],"Bid":[41,28,20,54,20,29,14,31,37,149,20,10,43,44,28,34,23,22,18,7,5,18,11,26,37,18,31,11,16,32,0],"symbol":"au2506","datetime":"2025-04-02 00:36:00","delta":286.0,"close":733.14,"open":733.36,"high":733.42,"low":732.82,"volume":2278,"dj":0,"dayma":736.3193442623,"delta累计":-5372.0} +{"price":["733.08","733.1","733.12","733.14","733.16","733.18","733.2","733.22","733.26","733.28","733.3","733.32","733.34","733.36","733.38","733.4","733.44","733.48","733.5","733.52","733.54","733.56","733.6","733.64","733.66","733.68","733.7","733.72","733.74","733.76","733.78","733.8","733.84","733.86","733.88","733.9","733.92","733.94","733.96","733.98","734.0","734.02","734.04","734.06","734.08","734.1","734.12"],"Ask":[0,0,4,3,47,0,44,4,7,16,25,0,59,26,27,17,6,24,36,19,175,41,21,8,7,109,24,41,174,162,57,13,4,9,0,6,32,90,16,29,24,103,71,49,30,82,36],"Bid":[7,9,7,19,11,3,0,17,39,70,75,2,42,16,0,46,5,43,34,52,0,0,0,0,0,29,44,117,194,132,16,22,0,14,52,65,41,55,56,49,18,57,96,112,62,7,0],"symbol":"au2506","datetime":"2025-04-02 00:39:00","delta":42.0,"close":733.94,"open":733.1,"high":734.12,"low":733.08,"volume":3811,"dj":4,"dayma":736.3,"delta累计":-5330.0} +{"price":["733.9","733.96","733.98","734.0","734.02","734.04","734.06","734.08","734.1","734.12","734.14","734.16","734.18","734.2","734.22","734.24","734.26","734.28"],"Ask":[0,15,9,43,7,11,124,150,83,138,204,181,12,115,91,71,5,23],"Bid":[25,22,47,13,116,70,131,145,98,41,174,30,28,36,72,19,0,0],"symbol":"au2506","datetime":"2025-04-02 00:42:00","delta":215.0,"close":734.16,"open":733.98,"high":734.28,"low":733.9,"volume":2554,"dj":0,"dayma":736.2827419355,"delta累计":-5115.0} +{"price":["733.58","733.6","733.62","733.64","733.66","733.68","733.7","733.72","733.74","733.76","733.78","733.8","733.82","733.84","733.86","733.88","733.9","733.92","733.94","733.96","733.98","734.0","734.02","734.04","734.06","734.08","734.1","734.12","734.14","734.16","734.18","734.2","734.22","734.24"],"Ask":[0,39,65,48,0,6,62,35,43,34,14,45,5,99,35,18,49,0,0,9,0,7,11,16,12,49,37,23,35,21,22,28,0,8],"Bid":[15,31,59,6,70,78,87,47,33,29,67,63,37,90,54,63,29,7,47,0,30,54,40,6,59,70,28,12,26,10,9,14,23,12],"symbol":"au2506","datetime":"2025-04-02 00:45:00","delta":-430.0,"close":733.6,"open":734.18,"high":734.24,"low":733.58,"volume":2490,"dj":-1,"dayma":736.26128,"delta累计":-5545.0} +{"price":["733.54","733.56","733.58","733.6","733.62","733.64","733.66","733.68","733.7","733.72","733.74","733.76","733.78","733.8","733.82","733.84","733.86","733.88","733.9","733.92","733.94","733.96","733.98"],"Ask":[0,1,7,103,48,17,13,8,51,68,47,40,17,49,66,68,44,65,46,19,13,18,66],"Bid":[8,21,33,38,20,35,22,29,42,7,19,25,0,77,48,23,30,25,29,48,32,11,2],"symbol":"au2506","datetime":"2025-04-02 00:48:00","delta":250.0,"close":733.86,"open":733.6,"high":733.98,"low":733.54,"volume":1623,"dj":0,"dayma":736.2422222222,"delta累计":-5295.0} +{"price":["733.88","733.9","733.92","733.94","733.96","733.98","734.0","734.02","734.04","734.06","734.08","734.1","734.12","734.14","734.16","734.18","734.2","734.22"],"Ask":[0,13,25,38,54,31,36,18,6,10,17,97,68,91,49,20,81,15],"Bid":[17,8,25,36,19,12,32,4,0,126,52,45,38,96,31,24,27,3],"symbol":"au2506","datetime":"2025-04-02 00:51:00","delta":74.0,"close":734.1,"open":733.9,"high":734.22,"low":733.88,"volume":1343,"dj":0,"dayma":736.2253543307,"delta累计":-5221.0} +{"price":["733.86","733.88","733.9","733.92","733.94","733.96","733.98","734.0","734.02","734.04","734.06","734.08","734.1","734.12","734.14","734.16","734.18","734.2","734.22","734.24"],"Ask":[0,1,7,14,15,15,47,19,33,38,27,56,62,25,42,24,19,48,23,11],"Bid":[13,28,28,17,61,10,49,127,29,21,113,45,14,39,21,5,12,56,19,0],"symbol":"au2506","datetime":"2025-04-02 00:54:00","delta":-181.0,"close":734.18,"open":734.12,"high":734.24,"low":733.86,"volume":1366,"dj":0,"dayma":736.209375,"delta累计":-5402.0} +{"price":["733.84","733.86","733.88","733.9","733.92","733.94","733.96","733.98","734.0","734.02","734.04","734.06","734.08","734.1","734.12","734.14","734.16","734.18","734.2","734.22"],"Ask":[0,0,16,27,48,25,12,77,96,0,11,8,9,40,21,0,25,9,24,6],"Bid":[1,13,68,4,31,52,32,79,21,20,50,19,20,6,11,8,11,15,20,0],"symbol":"au2506","datetime":"2025-04-02 00:57:00","delta":-27.0,"close":733.88,"open":734.2,"high":734.22,"low":733.84,"volume":1023,"dj":0,"dayma":736.1913178295,"delta累计":-5429.0} +{"price":["733.58","733.6","733.62","733.64","733.66","733.68","733.7","733.72","733.74","733.76","733.78","733.8","733.82","733.84","733.86"],"Ask":[0,0,28,82,23,28,46,82,35,22,71,21,24,22,0],"Bid":[6,69,48,28,47,81,123,55,47,31,55,29,32,10,8],"symbol":"au2506","datetime":"2025-04-02 01:00:00","delta":-185.0,"close":733.7,"open":733.86,"high":733.88,"low":733.58,"volume":1237,"dj":0,"dayma":736.1721538462,"delta累计":-5614.0} +{"price":["733.66","733.68","733.7","733.72","733.74","733.76","733.78","733.8","733.82","733.84","733.86","733.88","733.9","733.92","733.94","733.96","733.98"],"Ask":[0,25,3,37,21,32,12,11,32,4,34,55,46,71,28,25,25],"Bid":[15,24,28,32,37,25,8,6,15,7,6,64,58,51,58,0,21],"symbol":"au2506","datetime":"2025-04-02 01:03:00","delta":6.0,"close":733.88,"open":733.66,"high":733.98,"low":733.66,"volume":1010,"dj":0,"dayma":736.1546564885,"delta累计":-5608.0} +{"price":["733.68","733.7","733.72","733.74","733.76","733.78","733.8","733.82","733.84","733.86","733.88","733.92"],"Ask":[0,24,34,41,68,23,45,12,9,10,8,1],"Bid":[25,19,52,18,34,16,32,34,6,13,1,0],"symbol":"au2506","datetime":"2025-04-02 01:06:00","delta":25.0,"close":733.72,"open":733.88,"high":733.92,"low":733.68,"volume":568,"dj":0,"dayma":736.1362121212,"delta累计":-5583.0} +{"price":["733.36","733.38","733.4","733.42","733.44","733.46","733.48","733.5","733.52","733.54","733.56","733.58","733.6","733.62","733.64","733.66","733.68","733.7","733.72","733.74","733.76","733.78","733.8","733.82","733.84","733.86","733.88","733.9","733.92","733.94"],"Ask":[0,2,12,29,21,7,8,12,23,11,5,14,12,27,21,19,18,8,9,26,6,24,22,53,6,5,7,37,19,18],"Bid":[27,29,38,38,3,21,21,33,13,14,20,33,16,18,0,14,9,9,9,18,49,60,24,13,28,28,16,10,0,0],"symbol":"au2506","datetime":"2025-04-02 01:09:00","delta":-130.0,"close":733.68,"open":733.72,"high":733.94,"low":733.36,"volume":1207,"dj":0,"dayma":736.1177443609,"delta累计":-5713.0} +{"price":["733.6","733.62","733.64","733.66","733.68","733.7","733.72","733.74","733.76","733.78","733.8","733.82","733.84","733.86","733.88","733.9","733.92"],"Ask":[0,0,15,42,11,29,54,37,21,11,27,36,15,3,25,16,23],"Bid":[5,24,23,17,9,54,27,32,23,6,34,46,13,0,28,7,0],"symbol":"au2506","datetime":"2025-04-02 01:12:00","delta":17.0,"close":733.88,"open":733.66,"high":733.92,"low":733.6,"volume":797,"dj":0,"dayma":736.1010447761,"delta累计":-5696.0} +{"price":["733.68","733.7","733.72","733.74","733.76","733.78","733.8","733.82","733.84","733.86","733.88","733.9","733.92","733.94","733.96","733.98","734.0","734.04"],"Ask":[0,13,20,11,39,20,2,46,29,29,50,42,23,10,3,4,56,47],"Bid":[10,0,20,4,23,13,12,32,31,31,22,14,0,9,15,6,10,0],"symbol":"au2506","datetime":"2025-04-02 01:15:00","delta":192.0,"close":733.98,"open":733.86,"high":734.04,"low":733.68,"volume":740,"dj":0,"dayma":736.0853333333,"delta累计":-5504.0} +{"price":["733.9","733.92","733.94","733.96","733.98","734.0","734.02","734.04","734.06","734.08","734.1","734.12","734.14","734.16","734.18","734.2","734.22"],"Ask":[0,0,9,24,48,20,47,30,32,69,40,17,33,11,46,32,29],"Bid":[3,1,89,32,30,24,14,36,30,55,22,7,6,19,26,29,5],"symbol":"au2506","datetime":"2025-04-02 01:18:00","delta":59.0,"close":734.16,"open":734.0,"high":734.22,"low":733.9,"volume":1012,"dj":0,"dayma":736.0711764706,"delta累计":-5445.0} +{"price":["734.04","734.06","734.08","734.1","734.12","734.14","734.16","734.18","734.2","734.22","734.24","734.26","734.28","734.3","734.32","734.36","734.38","734.4","734.42","734.44","734.46","734.48"],"Ask":[0,3,6,6,15,5,27,24,32,52,66,43,51,54,80,11,14,20,19,52,22,31],"Bid":[14,17,18,18,15,40,14,23,85,37,74,21,62,36,0,11,0,7,43,13,12,0],"symbol":"au2506","datetime":"2025-04-02 01:21:00","delta":73.0,"close":734.48,"open":734.16,"high":734.48,"low":734.04,"volume":1277,"dj":0,"dayma":736.0595620438,"delta累计":-5372.0} +{"price":["734.34","734.36","734.38","734.4","734.42","734.44","734.46","734.48","734.5","734.52","734.54","734.56","734.58"],"Ask":[5,5,2,17,11,34,44,67,80,84,59,14,28],"Bid":[13,3,0,20,47,62,122,49,62,33,46,10,0],"symbol":"au2506","datetime":"2025-04-02 01:24:00","delta":-17.0,"close":734.48,"open":734.48,"high":734.58,"low":734.34,"volume":986,"dj":0,"dayma":736.048115942,"delta累计":-5389.0} +{"price":["734.44","734.46","734.48","734.5","734.52","734.54","734.56","734.58","734.6","734.62","734.64","734.66","734.68","734.7","734.72","734.74","734.76"],"Ask":[0,22,12,60,27,33,39,43,84,16,14,58,15,72,25,9,4],"Bid":[14,21,57,65,30,21,41,43,20,23,19,22,49,29,44,10,0],"symbol":"au2506","datetime":"2025-04-02 01:27:00","delta":25.0,"close":734.68,"open":734.5,"high":734.76,"low":734.44,"volume":1150,"dj":0,"dayma":736.0382733813,"delta累计":-5364.0} +{"price":["734.58","734.6","734.62","734.64","734.66","734.68","734.7","734.72","734.74","734.76","734.78","734.8","734.82","734.84"],"Ask":[0,19,17,22,23,36,34,42,85,78,44,21,9,69],"Bid":[7,3,31,10,42,41,69,67,75,39,53,25,5,6],"symbol":"au2506","datetime":"2025-04-02 01:30:00","delta":26.0,"close":734.76,"open":734.72,"high":734.84,"low":734.58,"volume":1067,"dj":0,"dayma":736.0291428571,"delta累计":-5338.0} +{"price":["734.44","734.46","734.48","734.5","734.52","734.54","734.56","734.58","734.6","734.62","734.64","734.66","734.68","734.7","734.72","734.74","734.76","734.78","734.8","734.82"],"Ask":[0,7,1,14,9,5,11,14,46,41,30,9,3,25,12,12,22,59,15,8],"Bid":[20,9,4,22,44,39,56,30,38,31,13,27,1,60,36,38,37,34,4,0],"symbol":"au2506","datetime":"2025-04-02 01:33:00","delta":-200.0,"close":734.54,"open":734.74,"high":734.82,"low":734.44,"volume":957,"dj":-1,"dayma":736.0185815603,"delta累计":-5538.0} +{"price":["734.36","734.38","734.4","734.42","734.44","734.46","734.48","734.5","734.52","734.54","734.56"],"Ask":[0,15,20,41,33,48,38,63,32,25,13],"Bid":[1,44,58,63,58,42,16,49,19,12,0],"symbol":"au2506","datetime":"2025-04-02 01:36:00","delta":-34.0,"close":734.4,"open":734.52,"high":734.56,"low":734.36,"volume":742,"dj":0,"dayma":736.0071830986,"delta累计":-5572.0} +{"price":["734.32","734.34","734.36","734.38","734.4","734.42","734.44","734.46","734.48","734.5","734.52","734.54","734.56","734.58","734.6","734.64"],"Ask":[0,5,25,4,7,37,17,53,52,65,31,20,15,6,0,7],"Bid":[3,23,8,5,24,24,30,32,40,32,19,13,0,0,9,0],"symbol":"au2506","datetime":"2025-04-02 01:39:00","delta":82.0,"close":734.6,"open":734.44,"high":734.64,"low":734.32,"volume":702,"dj":0,"dayma":735.9973426573,"delta累计":-5490.0} +{"price":["734.4","734.42","734.44","734.46","734.48","734.5","734.52","734.54","734.56","734.58","734.6","734.62","734.64","734.66","734.68"],"Ask":[0,32,94,2,14,35,1,2,20,16,29,25,13,2,7],"Bid":[68,32,4,17,13,18,5,11,52,28,33,37,12,0,0],"symbol":"au2506","datetime":"2025-04-02 01:42:00","delta":-38.0,"close":734.48,"open":734.62,"high":734.68,"low":734.4,"volume":671,"dj":0,"dayma":735.9868055556,"delta累计":-5528.0} +{"price":["734.38","734.4","734.42","734.44","734.46","734.48","734.5","734.52","734.54","734.56"],"Ask":[0,6,21,10,12,16,38,62,13,14],"Bid":[3,21,6,12,11,14,33,15,18,2],"symbol":"au2506","datetime":"2025-04-02 01:45:00","delta":57.0,"close":734.52,"open":734.48,"high":734.56,"low":734.38,"volume":337,"dj":0,"dayma":735.9766896552,"delta累计":-5471.0} +{"price":["734.44","734.46","734.48","734.5","734.52","734.54","734.56","734.58","734.6","734.62","734.64","734.66","734.68","734.7","734.72","734.74","734.76","734.78","734.8","734.82","734.84"],"Ask":[0,22,14,67,36,2,16,7,10,6,14,23,2,5,0,25,38,13,41,18,7],"Bid":[17,19,20,8,12,4,5,2,0,10,2,0,2,3,11,40,8,21,18,1,0],"symbol":"au2506","datetime":"2025-04-02 01:48:00","delta":163.0,"close":734.82,"open":734.52,"high":734.84,"low":734.44,"volume":616,"dj":0,"dayma":735.9687671233,"delta累计":-5308.0} +{"price":["734.68","734.7","734.72","734.74","734.76","734.78","734.8","734.82"],"Ask":[0,31,27,22,26,14,20,18],"Bid":[23,51,35,27,24,11,26,0],"symbol":"au2506","datetime":"2025-04-02 01:51:00","delta":-39.0,"close":734.78,"open":734.82,"high":734.82,"low":734.68,"volume":388,"dj":0,"dayma":735.9606802721,"delta累计":-5347.0} +{"price":["734.7","734.72","734.74","734.76","734.78","734.8"],"Ask":[3,43,59,20,45,12],"Bid":[50,19,40,25,2,0],"symbol":"au2506","datetime":"2025-04-02 01:54:00","delta":46.0,"close":734.8,"open":734.78,"high":734.8,"low":734.7,"volume":352,"dj":0,"dayma":735.9528378378,"delta累计":-5301.0} +{"price":["734.72","734.74","734.76","734.78","734.8","734.82"],"Ask":[1,56,20,18,48,18],"Bid":[25,26,24,15,24,8],"symbol":"au2506","datetime":"2025-04-02 01:57:00","delta":39.0,"close":734.76,"open":734.78,"high":734.82,"low":734.72,"volume":299,"dj":0,"dayma":735.9448322148,"delta累计":-5262.0} +{"price":["734.7","734.72","734.74","734.76","734.78","734.8","734.82","734.84","734.86","734.88","734.9","734.92","734.94","734.96","734.98","735.0","735.04","735.06"],"Ask":[10,3,18,21,39,30,30,15,11,11,4,3,31,51,13,5,72,26],"Bid":[24,21,33,32,28,9,3,0,0,28,14,9,73,24,0,0,0,0],"symbol":"au2506","datetime":"2025-04-02 02:00:00","delta":95.0,"close":735.06,"open":734.76,"high":735.06,"low":734.7,"volume":773,"dj":3,"dayma":735.9389333333,"delta累计":-5167.0} +{"price":["734.98","735.0","735.02","735.04","735.06","735.08","735.1","735.12","735.14","735.16","735.18","735.2","735.22","735.24","735.26","735.28","735.3","735.32","735.34","735.36","735.38","735.4","735.42","735.44","735.46","735.48","735.5","735.52","735.54","735.56","735.58","735.6","735.62","735.64","735.66","735.68","735.7","735.72","735.74","735.76","735.78","735.8","735.82","735.84","735.86","735.9","735.92","735.94","735.96","735.98","736.0","736.02","736.06","736.1","736.12","736.16","736.18","736.22","736.24","736.26","736.28","736.3","736.32","736.34","736.36","736.38","736.4"],"Ask":[5,4,14,1,68,45,41,12,21,27,45,3,15,3,2,1,0,6,0,20,28,7,0,25,51,26,41,14,21,31,9,35,62,3,16,9,1,0,0,21,8,0,13,94,82,31,39,62,28,4,131,5,6,0,11,8,14,5,38,8,12,35,2,3,0,22,11],"Bid":[15,57,9,12,0,0,7,8,49,22,0,0,41,41,0,0,7,10,33,7,11,78,3,35,45,83,0,34,51,70,21,49,62,5,5,0,0,2,10,33,29,38,131,32,36,20,0,0,2,0,4,3,0,23,0,0,12,27,20,19,0,7,0,72,15,11,0],"symbol":"au2506","datetime":"2025-04-02 02:03:00","delta":-11.0,"close":736.38,"open":735.06,"high":736.4,"low":734.98,"volume":2972,"dj":0,"dayma":735.9418543046,"delta累计":-5178.0} +{"price":["736.08","736.12","736.14","736.16","736.18","736.2","736.22","736.24","736.26","736.28","736.3","736.32","736.34","736.36","736.38","736.4","736.42","736.44"],"Ask":[0,15,69,59,36,45,53,2,2,8,18,93,37,52,27,28,48,20],"Bid":[18,38,16,88,42,61,19,11,7,30,114,128,21,88,32,58,7,0],"symbol":"au2506","datetime":"2025-04-02 02:06:00","delta":-166.0,"close":736.16,"open":736.38,"high":736.44,"low":736.08,"volume":1469,"dj":0,"dayma":735.9432894737,"delta累计":-5344.0} +{"price":["736.12","736.14","736.16","736.18","736.2","736.22","736.24","736.26","736.28","736.3","736.32","736.34","736.36","736.38","736.4","736.42","736.44","736.46","736.48"],"Ask":[0,0,21,6,9,3,0,6,11,68,38,17,29,13,22,0,22,13,14],"Bid":[4,40,7,0,5,19,17,64,31,48,80,28,11,16,10,74,16,0,0],"symbol":"au2506","datetime":"2025-04-02 02:09:00","delta":-178.0,"close":736.32,"open":736.16,"high":736.48,"low":736.12,"volume":870,"dj":0,"dayma":735.945751634,"delta累计":-5522.0} +{"price":["736.22","736.26","736.28","736.3","736.32","736.34","736.36","736.38","736.4","736.42","736.44","736.46","736.48","736.5","736.52"],"Ask":[0,13,9,23,2,25,33,21,29,20,28,55,33,44,9],"Bid":[16,33,10,17,24,42,38,11,25,64,40,84,23,5,0],"symbol":"au2506","datetime":"2025-04-02 02:12:00","delta":-88.0,"close":736.26,"open":736.3,"high":736.52,"low":736.22,"volume":827,"dj":0,"dayma":735.9477922078,"delta累计":-5610.0} +{"price":["736.26","736.28","736.3","736.32","736.34","736.36","736.38","736.4","736.42","736.44","736.46","736.48"],"Ask":[10,1,6,17,22,28,23,23,6,14,12,13],"Bid":[21,0,1,40,48,21,20,7,10,7,0,0],"symbol":"au2506","datetime":"2025-04-02 02:15:00","delta":0.0,"close":736.42,"open":736.26,"high":736.48,"low":736.26,"volume":385,"dj":0,"dayma":735.9508387097,"delta累计":-5610.0} +{"price":["735.68","735.7","735.72","735.74","735.76","735.78","735.8","735.82","735.84","735.86","735.88","735.92","735.94","735.96","736.02","736.04","736.06","736.08","736.1","736.12","736.14","736.16","736.2","736.22","736.24","736.26","736.28","736.3","736.32","736.34","736.36","736.38","736.4","736.42","736.44","736.46"],"Ask":[14,41,1,8,17,11,3,33,25,0,0,0,0,0,0,45,14,10,23,3,0,0,0,0,9,4,18,8,23,1,0,26,27,6,5,1],"Bid":[44,3,4,2,24,1,2,13,6,5,16,8,13,13,52,12,30,6,5,11,8,1,7,2,8,15,23,19,26,16,1,40,15,9,0,0],"symbol":"au2506","datetime":"2025-04-02 02:18:00","delta":-84.0,"close":735.82,"open":736.42,"high":736.46,"low":735.68,"volume":888,"dj":-6,"dayma":735.95,"delta累计":-5694.0} +{"price":["735.88","735.9","735.92","735.94","735.96","735.98","736.0","736.02","736.04","736.06","736.08","736.1","736.12","736.14","736.16","736.18","736.2","736.22","736.24","736.26","736.28","736.3"],"Ask":[16,4,2,5,6,22,29,1,1,11,7,6,29,28,4,17,10,20,31,19,26,24],"Bid":[0,0,7,6,1,5,0,17,5,20,0,8,12,10,2,3,15,34,44,5,31,0],"symbol":"au2506","datetime":"2025-04-02 02:21:00","delta":93.0,"close":736.3,"open":735.88,"high":736.3,"low":735.88,"volume":619,"dj":1,"dayma":735.9522292994,"delta累计":-5601.0} +{"price":["736.02","736.04","736.06","736.08","736.1","736.12","736.14","736.16","736.18","736.2","736.24","736.26","736.28","736.32"],"Ask":[2,3,23,26,62,25,19,15,4,0,0,7,0,3],"Bid":[11,7,23,78,51,23,33,3,1,1,19,4,8,0],"symbol":"au2506","datetime":"2025-04-02 02:24:00","delta":-73.0,"close":736.1,"open":736.32,"high":736.32,"low":736.02,"volume":485,"dj":0,"dayma":735.953164557,"delta累计":-5674.0} +{"price":["735.94","735.96","735.98","736.0","736.02","736.04","736.06","736.08","736.1","736.12","736.14","736.18","736.2","736.22","736.24","736.26","736.28","736.3","736.32"],"Ask":[0,4,5,12,34,19,17,2,34,8,5,7,27,31,7,11,15,59,6],"Bid":[7,14,15,21,18,3,18,6,10,16,2,7,10,4,3,9,34,26,2],"symbol":"au2506","datetime":"2025-04-02 02:27:00","delta":78.0,"close":736.28,"open":736.1,"high":736.32,"low":735.94,"volume":568,"dj":1,"dayma":735.9552201258,"delta累计":-5596.0} +{"price":["736.66"],"Ask":[0],"Bid":[169],"symbol":"au2506","datetime":"2025-04-02 09:00:00","delta":-169.0,"close":736.66,"open":736.66,"high":736.66,"low":736.66,"volume":169,"dj":0,"dayma":734.3090196078,"delta累计":-892.0} +{"price":["736.12","736.16","736.2","736.22","736.24","736.26","736.28","736.3","736.32","736.36","736.38","736.4","736.42","736.44","736.46","736.48","736.5","736.52","736.54","736.56","736.58","736.6","736.62","736.66","736.68","736.7","736.72","736.74","736.76","736.78","736.8","736.82","736.84","736.86","736.88","736.9","736.92","736.96","736.98","737.0","737.02","737.06","737.1","737.12","737.14","737.18"],"Ask":[0,40,35,23,49,0,0,75,17,44,47,88,53,89,68,99,100,181,74,149,81,2,12,40,41,74,0,21,20,31,0,44,60,19,162,131,119,0,77,104,0,49,46,36,70,96],"Bid":[25,28,0,0,10,3,9,0,144,59,15,140,69,64,205,97,210,139,12,64,0,21,0,74,0,44,53,24,27,0,129,8,97,64,13,222,40,52,34,31,60,0,80,41,0,0],"symbol":"au2506","datetime":"2025-04-02 09:03:00","delta":159.0,"close":736.44,"open":736.7,"high":737.18,"low":736.12,"volume":5720,"dj":0,"dayma":734.35,"delta累计":-733.0} +{"price":["736.3","736.32","736.34","736.36","736.38","736.4","736.42","736.44","736.46","736.48","736.5","736.52","736.54","736.56","736.58","736.6","736.64","736.66","736.68","736.7","736.72","736.74","736.76","736.78","736.8","736.82","736.84","736.86","736.88","736.9","736.92","736.94","736.96","736.98","737.0","737.02","737.04","737.06","737.08","737.1","737.12","737.14","737.16","737.18","737.2","737.22","737.24"],"Ask":[0,21,13,29,0,81,66,23,212,82,164,67,25,7,0,15,0,69,0,9,10,46,96,15,26,2,19,7,0,11,9,25,41,35,13,27,19,22,34,93,18,56,42,34,101,10,34],"Bid":[7,27,12,0,49,69,49,86,60,92,36,42,27,0,28,5,4,17,4,29,43,128,17,10,0,0,0,0,43,42,18,0,78,0,0,0,0,44,24,46,14,64,120,41,254,0,0],"symbol":"au2506","datetime":"2025-04-02 09:06:00","delta":99.0,"close":737.1,"open":736.4,"high":737.24,"low":736.3,"volume":3591,"dj":3,"dayma":734.4018867925,"delta累计":-634.0} +{"price":["737.02","737.04","737.06","737.08","737.1","737.12","737.14","737.16","737.18","737.2","737.22","737.24","737.26","737.28","737.3","737.32","737.34","737.36","737.38","737.4","737.42","737.44","737.46","737.48","737.5","737.52"],"Ask":[0,0,27,41,142,65,12,35,96,88,31,54,77,93,112,86,6,21,111,225,201,204,24,190,73,9],"Bid":[5,5,40,88,159,10,6,58,29,97,87,65,82,91,18,100,162,16,167,111,223,413,32,165,14,0],"symbol":"au2506","datetime":"2025-04-02 09:09:00","delta":-220.0,"close":737.44,"open":737.12,"high":737.52,"low":737.02,"volume":4778,"dj":0,"dayma":734.4581481481,"delta累计":-854.0} +{"price":["737.26","737.28","737.3","737.32","737.34","737.36","737.38","737.4","737.42","737.44","737.46","737.48","737.5","737.52","737.54","737.56","737.58","737.6","737.62","737.64","737.66","737.68","737.7","737.72","737.74"],"Ask":[0,0,5,136,49,17,40,209,31,72,111,233,307,189,26,14,19,112,105,176,102,31,115,51,39],"Bid":[49,4,303,136,68,11,80,158,172,112,85,73,157,122,105,38,124,231,74,32,7,43,61,4,0],"symbol":"au2506","datetime":"2025-04-02 09:12:00","delta":-60.0,"close":737.66,"open":737.46,"high":737.74,"low":737.26,"volume":4700,"dj":0,"dayma":734.5163636364,"delta累计":-914.0} +{"price":["737.4","737.42","737.44","737.46","737.48","737.5","737.52","737.54","737.56","737.58","737.6","737.62","737.64","737.66","737.68","737.7","737.72","737.74","737.76","737.78","737.8","737.82","737.84","737.86","737.88","737.9","737.94"],"Ask":[0,0,10,0,9,85,180,35,27,6,11,0,12,24,56,57,90,142,214,254,72,89,26,61,163,35,13],"Bid":[39,34,0,38,40,80,31,43,39,32,0,33,0,57,135,167,153,155,73,262,227,84,42,88,75,11,0],"symbol":"au2506","datetime":"2025-04-02 09:15:00","delta":-267.0,"close":737.76,"open":737.66,"high":737.94,"low":737.4,"volume":4037,"dj":0,"dayma":734.5742857143,"delta累计":-1181.0} +{"price":["737.48","737.5","737.54","737.56","737.58","737.6","737.62","737.64","737.66","737.68","737.7","737.72","737.74","737.76","737.78","737.8","737.82","737.84","737.86","737.88","737.9"],"Ask":[0,0,7,47,286,123,8,54,63,59,129,58,108,45,39,179,53,77,120,158,37],"Bid":[26,55,89,160,83,94,33,80,56,16,135,115,107,78,42,135,37,45,28,39,6],"symbol":"au2506","datetime":"2025-04-02 09:18:00","delta":191.0,"close":737.74,"open":737.76,"high":737.9,"low":737.48,"volume":3284,"dj":0,"dayma":734.6298245614,"delta累计":-990.0} +{"price":["737.48","737.5","737.52","737.54","737.56","737.58","737.6","737.64","737.66","737.68","737.7","737.72","737.74","737.76","737.78","737.8","737.82","737.84","737.86","737.88","737.9","737.92","737.94","737.96","737.98","738.0","738.02","738.04","738.06","738.08","738.1","738.12","738.14","738.16","738.18","738.2","738.22","738.24","738.26","738.28","738.3","738.32","738.34","738.36"],"Ask":[0,27,20,29,8,26,14,51,50,50,24,53,58,111,31,107,0,7,0,31,30,6,29,76,258,69,20,15,0,21,67,6,16,23,6,106,30,24,0,54,89,218,76,4],"Bid":[3,64,69,22,15,27,66,33,30,103,46,76,88,24,66,0,28,0,24,98,23,43,3,24,0,54,0,0,12,0,77,0,10,21,10,30,37,62,68,136,108,15,12,7],"symbol":"au2506","datetime":"2025-04-02 09:21:00","delta":306.0,"close":738.22,"open":737.78,"high":738.36,"low":737.48,"volume":3894,"dj":1,"dayma":734.6917241379,"delta累计":-684.0} +{"price":["737.52","737.54","737.56","737.58","737.6","737.64","737.66","737.68","737.7","737.72","737.74","737.76","737.78","737.8","737.82","737.84","737.86","737.88","737.9","737.92","737.94","737.96","737.98","738.0","738.02","738.04","738.06","738.08","738.1","738.12","738.14","738.18","738.2","738.22","738.24","738.26"],"Ask":[0,43,14,49,25,102,0,7,103,24,12,50,51,89,68,12,30,18,21,32,18,91,68,71,18,38,41,131,62,9,25,0,27,4,30,90],"Bid":[33,0,2,10,68,6,46,12,106,20,19,23,61,6,64,46,70,70,40,19,75,51,94,24,14,127,50,40,44,69,7,19,56,25,56,0],"symbol":"au2506","datetime":"2025-04-02 09:24:00","delta":1.0,"close":737.98,"open":738.24,"high":738.26,"low":737.52,"volume":3242,"dj":0,"dayma":734.7474576271,"delta累计":-683.0} +{"price":["737.74","737.76","737.78","737.8","737.82","737.84","737.86","737.88","737.9","737.92","737.94","737.96","737.98","738.02","738.04","738.06","738.08","738.1","738.14","738.16"],"Ask":[0,0,17,20,31,39,51,91,80,28,28,25,130,22,3,21,18,14,7,27],"Bid":[11,47,16,26,17,73,180,32,46,23,13,10,56,0,20,12,2,30,0,0],"symbol":"au2506","datetime":"2025-04-02 09:27:00","delta":38.0,"close":738.06,"open":737.98,"high":738.16,"low":737.74,"volume":1363,"dj":0,"dayma":734.8026666667,"delta累计":-645.0} +{"price":["737.86","737.88","737.9","737.92","737.94","737.96","737.98","738.0","738.02","738.04","738.06","738.08"],"Ask":[6,87,117,28,39,85,150,250,64,127,69,2],"Bid":[0,26,105,42,31,158,189,108,52,20,22,0],"symbol":"au2506","datetime":"2025-04-02 09:30:00","delta":271.0,"close":737.96,"open":738.02,"high":738.08,"low":737.86,"volume":1875,"dj":0,"dayma":734.8544262295,"delta累计":-374.0} +{"price":["737.96","737.98","738.0","738.02","738.04","738.06","738.08","738.1","738.12","738.14","738.16","738.18","738.2","738.22","738.24","738.26","738.28","738.3","738.34","738.38","738.4","738.42","738.44","738.46","738.48","738.5"],"Ask":[2,14,45,28,48,30,41,43,87,117,115,51,58,11,22,139,26,103,64,47,27,0,149,13,26,52],"Bid":[21,1,101,27,33,43,5,68,111,162,11,1,80,16,2,75,50,33,0,118,12,21,20,93,37,0],"symbol":"au2506","datetime":"2025-04-02 09:33:00","delta":217.0,"close":738.44,"open":737.96,"high":738.5,"low":737.96,"volume":2649,"dj":0,"dayma":734.9122580645,"delta累计":-157.0} +{"price":["737.82","737.84","737.86","737.88","737.9","737.92","737.94","737.96","737.98","738.0","738.02","738.04","738.06","738.08","738.1","738.12","738.14","738.16","738.18","738.2","738.24","738.28","738.3","738.32","738.34","738.36","738.38","738.4","738.44"],"Ask":[0,14,40,55,100,28,0,6,16,48,13,8,52,21,138,169,144,85,37,13,0,0,2,0,68,30,16,0,18],"Bid":[40,48,28,22,10,0,46,42,18,82,49,70,73,87,110,134,31,72,78,0,50,15,6,65,22,17,5,17,13],"symbol":"au2506","datetime":"2025-04-02 09:36:00","delta":-129.0,"close":737.82,"open":738.44,"high":738.44,"low":737.82,"volume":2587,"dj":-1,"dayma":734.9584126984,"delta累计":-286.0} +{"price":["737.1","737.12","737.14","737.16","737.18","737.2","737.22","737.24","737.26","737.28","737.3","737.32","737.34","737.36","737.38","737.4","737.42","737.44","737.46","737.48","737.5","737.52","737.54","737.58","737.6","737.62","737.64","737.66","737.68","737.7","737.72","737.74","737.76","737.78","737.8"],"Ask":[81,0,0,21,67,124,105,16,84,48,105,29,259,84,59,0,8,30,43,0,29,17,64,0,4,33,3,0,49,21,58,62,60,2,89],"Bid":[63,7,15,161,81,15,29,61,65,31,205,166,69,22,0,87,15,6,3,41,27,33,31,14,25,28,16,21,53,108,149,34,9,55,24],"symbol":"au2506","datetime":"2025-04-02 09:39:00","delta":-115.0,"close":737.22,"open":737.8,"high":737.8,"low":737.1,"volume":3611,"dj":0,"dayma":734.99375,"delta累计":-401.0} +{"price":["737.0","737.04","737.06","737.08","737.1","737.12","737.14","737.16","737.18","737.2","737.22","737.24","737.26","737.28","737.3","737.32","737.34","737.36","737.38","737.4","737.42","737.44","737.46"],"Ask":[0,0,0,169,115,30,53,121,229,241,126,98,120,140,41,75,35,48,38,24,30,8,44],"Bid":[69,9,90,41,120,58,88,69,95,176,14,73,47,30,60,54,25,13,16,9,32,8,5],"symbol":"au2506","datetime":"2025-04-02 09:42:00","delta":584.0,"close":737.36,"open":737.2,"high":737.46,"low":737.0,"volume":3134,"dj":0,"dayma":735.0301538462,"delta累计":183.0} +{"price":["737.12","737.14","737.16","737.18","737.2","737.22","737.24","737.26","737.28","737.3","737.32","737.34","737.36","737.38","737.4","737.42","737.44","737.46","737.48","737.5","737.52","737.54","737.58"],"Ask":[0,5,47,38,16,14,7,7,7,8,17,19,20,32,35,176,43,92,11,19,30,14,37],"Bid":[24,49,34,20,8,22,23,6,26,40,24,27,88,46,189,70,14,70,0,1,73,22,0],"symbol":"au2506","datetime":"2025-04-02 09:45:00","delta":-182.0,"close":737.2,"open":737.4,"high":737.58,"low":737.12,"volume":1767,"dj":0,"dayma":735.063030303,"delta累计":1.0} +{"price":["737.04","737.08","737.1","737.12","737.14","737.16","737.18","737.2","737.22","737.24","737.26","737.28","737.3","737.32","737.34","737.36","737.38","737.4","737.42","737.44","737.46","737.48","737.5","737.52","737.54","737.56","737.58","737.6","737.62","737.66","737.68","737.7","737.72"],"Ask":[0,6,14,23,1,0,6,36,41,12,5,39,21,22,0,13,34,29,39,22,24,67,75,15,13,55,44,42,49,19,75,19,25],"Bid":[27,10,33,40,12,2,6,40,19,20,18,12,0,0,4,1,18,20,40,23,30,17,49,21,40,23,49,12,0,28,8,25,0],"symbol":"au2506","datetime":"2025-04-02 09:48:00","delta":238.0,"close":737.7,"open":737.2,"high":737.72,"low":737.04,"volume":1624,"dj":0,"dayma":735.1023880597,"delta累计":239.0} +{"price":["737.5","737.52","737.54","737.56","737.58","737.6","737.62","737.64","737.66","737.68","737.7","737.72","737.74","737.76","737.78","737.8","737.82","737.84","737.86"],"Ask":[0,3,10,17,30,54,32,48,32,37,24,0,31,0,15,18,7,5,12],"Bid":[23,26,34,25,39,43,51,37,56,40,5,28,32,33,6,0,15,16,30],"symbol":"au2506","datetime":"2025-04-02 09:51:00","delta":-164.0,"close":737.58,"open":737.72,"high":737.86,"low":737.5,"volume":999,"dj":0,"dayma":735.1388235294,"delta累计":75.0} +{"price":["737.32","737.34","737.36","737.38","737.4","737.42","737.44","737.46","737.48","737.5","737.52","737.54","737.56","737.58","737.6","737.62","737.64","737.66","737.68","737.7","737.72"],"Ask":[0,14,3,41,152,25,4,36,7,15,0,14,18,20,108,10,8,41,26,22,20],"Bid":[13,12,31,17,100,40,94,30,1,10,55,1,27,26,48,12,17,27,35,12,7],"symbol":"au2506","datetime":"2025-04-02 09:54:00","delta":-31.0,"close":737.38,"open":737.56,"high":737.72,"low":737.32,"volume":1304,"dj":0,"dayma":735.1713043478,"delta累计":44.0} +{"price":["737.14","737.18","737.2","737.22","737.24","737.26","737.28","737.3","737.32","737.34","737.36","737.38","737.4","737.42","737.44","737.46","737.48","737.5","737.52","737.54","737.56","737.58","737.6","737.62","737.64","737.66"],"Ask":[0,21,0,17,13,9,17,8,8,22,40,28,115,43,40,50,56,45,10,8,27,17,7,0,21,12],"Bid":[28,0,11,8,16,11,11,75,6,18,123,54,66,30,52,5,26,29,11,38,10,8,3,56,0,10],"symbol":"au2506","datetime":"2025-04-02 09:57:00","delta":-71.0,"close":737.48,"open":737.38,"high":737.66,"low":737.14,"volume":1521,"dj":0,"dayma":735.2042857143,"delta累计":-27.0} +{"price":["737.46","737.48","737.5","737.52","737.54","737.56","737.58","737.6","737.62","737.64","737.66","737.68","737.7","737.72","737.74"],"Ask":[0,3,31,39,14,10,50,55,41,59,31,32,69,11,24],"Bid":[8,6,9,5,21,31,43,46,35,53,18,30,45,34,23],"symbol":"au2506","datetime":"2025-04-02 10:00:00","delta":62.0,"close":737.58,"open":737.48,"high":737.74,"low":737.46,"volume":981,"dj":0,"dayma":735.2377464789,"delta累计":35.0} +{"price":["737.26","737.3","737.32","737.34","737.36","737.38","737.4","737.42","737.44","737.46","737.48","737.5","737.52","737.54","737.56","737.58","737.6"],"Ask":[0,43,5,18,91,40,88,40,72,152,28,65,17,1,2,20,6],"Bid":[25,75,0,16,27,142,205,35,48,22,68,34,24,4,11,4,14],"symbol":"au2506","datetime":"2025-04-02 10:03:00","delta":-66.0,"close":737.44,"open":737.56,"high":737.6,"low":737.26,"volume":1589,"dj":0,"dayma":735.2683333333,"delta累计":-31.0} +{"price":["737.38","737.4","737.42","737.44","737.46","737.48","737.5","737.52","737.54","737.56","737.58","737.6","737.62","737.64","737.66","737.68","737.7","737.74","737.76","737.78","737.8","737.84","737.88","737.9","737.92","737.94","737.96"],"Ask":[4,18,11,6,15,25,33,55,13,0,27,92,67,74,88,18,28,7,29,29,38,23,15,21,0,57,8],"Bid":[17,9,1,10,18,33,64,7,0,10,8,67,51,39,7,3,22,53,26,9,9,0,26,0,20,0,0],"symbol":"au2506","datetime":"2025-04-02 10:06:00","delta":292.0,"close":737.96,"open":737.46,"high":737.96,"low":737.38,"volume":1372,"dj":0,"dayma":735.3052054795,"delta累计":261.0} +{"price":["737.34","737.36","737.38","737.4","737.42","737.44","737.46","737.48","737.5","737.52","737.56","737.58","737.6","737.64","737.66","737.68","737.7","737.72","737.74","737.76","737.78","737.8","737.82","737.84","737.86","737.88","737.9","737.92","737.94","737.98"],"Ask":[0,11,86,17,20,34,15,7,48,0,0,0,27,0,0,7,1,9,42,12,15,48,46,57,21,13,15,0,0,11],"Bid":[10,6,61,16,34,6,35,2,62,5,18,6,26,12,10,21,27,26,39,77,36,56,102,72,15,0,20,12,25,0],"symbol":"au2506","datetime":"2025-04-02 10:09:00","delta":-275.0,"close":737.46,"open":737.98,"high":737.98,"low":737.34,"volume":1487,"dj":-1,"dayma":735.3343243243,"delta累计":-14.0} +{"price":["737.34","737.36","737.38","737.4","737.42","737.44","737.46","737.48","737.5","737.52","737.54","737.56","737.58","737.6","737.62"],"Ask":[0,10,0,36,19,42,24,6,14,54,68,19,65,23,10],"Bid":[12,18,24,19,33,6,28,11,21,43,42,34,47,15,0],"symbol":"au2506","datetime":"2025-04-02 10:12:00","delta":37.0,"close":737.4,"open":737.44,"high":737.62,"low":737.34,"volume":812,"dj":0,"dayma":735.3618666667,"delta累计":23.0} +{"price":["737.3","737.32","737.34","737.36","737.38","737.4","737.42","737.44","737.46","737.48","737.5"],"Ask":[0,41,2,6,57,34,99,43,12,17,56],"Bid":[40,14,37,24,29,40,94,62,33,15,26],"symbol":"au2506","datetime":"2025-04-02 10:15:00","delta":-47.0,"close":737.42,"open":737.34,"high":737.5,"low":737.3,"volume":843,"dj":0,"dayma":735.3889473684,"delta累计":-24.0} +{"price":["737.42"],"Ask":[0],"Bid":[5],"symbol":"au2506","datetime":"2025-04-02 10:18:00","delta":-5.0,"close":737.42,"open":737.42,"high":737.42,"low":737.42,"volume":5,"dj":0,"dayma":735.4153246753,"delta累计":-29.0} +{"price":["736.78","736.8","736.82","736.84","736.86","736.88","736.9","736.92","736.94","736.96","736.98","737.0","737.02","737.04","737.06","737.08","737.1","737.12","737.16","737.18","737.2","737.26","737.28","737.3","737.32","737.34","737.36","737.38","737.4","737.42","737.44","737.46","737.48","737.5","737.52","737.54","737.56"],"Ask":[0,39,13,39,0,22,72,137,19,18,33,195,89,120,39,11,17,20,4,5,0,0,3,0,7,21,0,7,4,19,13,34,38,30,0,0,9],"Bid":[6,22,18,0,13,69,142,86,42,20,30,72,136,48,41,45,46,19,21,28,23,7,0,27,3,15,6,5,16,2,28,30,6,36,3,31,0],"symbol":"au2506","datetime":"2025-04-02 10:33:00","delta":-65.0,"close":737.04,"open":737.44,"high":737.56,"low":736.78,"volume":2335,"dj":-3,"dayma":735.4361538462,"delta累计":-94.0} +{"price":["736.88","736.9","736.92","736.94","736.96","736.98","737.0","737.02","737.04","737.06","737.08","737.1","737.12","737.14","737.16","737.2","737.22","737.24","737.26"],"Ask":[0,2,0,29,49,27,27,13,50,41,8,17,38,54,39,11,11,18,21],"Bid":[4,7,19,36,39,23,96,25,42,17,29,16,33,23,7,11,14,0,0],"symbol":"au2506","datetime":"2025-04-02 10:36:00","delta":14.0,"close":736.96,"open":737.02,"high":737.26,"low":736.88,"volume":998,"dj":0,"dayma":735.455443038,"delta累计":-80.0} +{"price":["736.94","736.96","736.98","737.0","737.02","737.04","737.06","737.08","737.1","737.12","737.14","737.16"],"Ask":[7,16,31,30,16,42,154,102,85,18,6,16],"Bid":[2,31,30,18,10,66,55,37,28,0,0,0],"symbol":"au2506","datetime":"2025-04-02 10:39:00","delta":246.0,"close":737.04,"open":736.98,"high":737.16,"low":736.94,"volume":892,"dj":0,"dayma":735.47525,"delta累计":166.0} +{"price":["736.44","736.52","736.54","736.56","736.58","736.6","736.62","736.64","736.66","736.68","736.7","736.72","736.74","736.76","736.78","736.8","736.82","736.84","736.86","736.88","736.9","736.92","736.94","736.96","736.98","737.0","737.02","737.06"],"Ask":[0,0,0,46,43,7,96,71,124,55,13,20,54,30,75,48,56,0,0,0,15,15,2,38,19,14,0,5],"Bid":[9,89,23,28,94,34,195,75,101,57,10,22,79,35,92,14,19,11,5,19,42,24,22,15,18,81,9,0],"symbol":"au2506","datetime":"2025-04-02 10:42:00","delta":-376.0,"close":736.44,"open":737.06,"high":737.06,"low":736.44,"volume":2146,"dj":-1,"dayma":735.4871604938,"delta累计":-210.0} +{"price":["736.42","736.44","736.46","736.48","736.5","736.52","736.54","736.56","736.58","736.6","736.62","736.64","736.66","736.68","736.7","736.72","736.74","736.76","736.78","736.8","736.82","736.84","736.86","736.88","736.9"],"Ask":[0,0,14,24,35,4,37,13,33,29,5,11,14,51,18,3,1,17,10,20,17,47,66,52,21],"Bid":[14,19,21,0,37,39,17,6,1,14,5,35,4,7,0,14,2,7,18,38,50,47,78,19,0],"symbol":"au2506","datetime":"2025-04-02 10:45:00","delta":50.0,"close":736.82,"open":736.44,"high":736.9,"low":736.42,"volume":1131,"dj":0,"dayma":735.5034146341,"delta累计":-160.0} +{"price":["736.76","736.78","736.8","736.82","736.84","736.86","736.88","736.9","736.92","736.94","736.96","736.98","737.0","737.02","737.04","737.06","737.08","737.1","737.12","737.14","737.16","737.18","737.2","737.22","737.24","737.26","737.28","737.3","737.34"],"Ask":[0,6,10,21,9,18,3,53,24,31,48,78,19,13,19,157,69,17,17,16,22,36,54,40,10,23,19,30,5],"Bid":[8,7,19,10,1,25,15,19,35,8,2,17,13,69,21,31,36,9,24,13,44,69,56,47,0,24,26,40,0],"symbol":"au2506","datetime":"2025-04-02 10:48:00","delta":179.0,"close":737.12,"open":736.8,"high":737.34,"low":736.76,"volume":1737,"dj":0,"dayma":735.5228915663,"delta累计":19.0} +{"price":["736.7","736.72","736.74","736.76","736.78","736.8","736.82","736.84","736.86","736.88","736.9","736.92","736.94","736.96","736.98","737.0","737.02","737.04","737.08"],"Ask":[0,0,5,12,96,19,26,100,33,19,41,29,11,25,5,56,22,7,0],"Bid":[50,3,4,35,35,39,18,39,36,16,19,19,14,10,8,40,16,23,2],"symbol":"au2506","datetime":"2025-04-02 10:51:00","delta":80.0,"close":736.76,"open":737.08,"high":737.08,"low":736.7,"volume":988,"dj":0,"dayma":735.5376190476,"delta累计":99.0} +{"price":["736.62","736.64","736.66","736.68","736.7","736.72","736.74","736.76","736.78","736.8","736.82","736.84","736.86"],"Ask":[10,9,21,20,60,21,61,76,27,19,10,11,9],"Bid":[25,14,17,18,76,64,80,64,11,5,16,3,4],"symbol":"au2506","datetime":"2025-04-02 10:54:00","delta":-43.0,"close":736.86,"open":736.74,"high":736.86,"low":736.62,"volume":815,"dj":0,"dayma":735.5531764706,"delta累计":56.0} +{"price":["736.78","736.8","736.82","736.84","736.86","736.88","736.9","736.92","736.94","736.96","736.98","737.0","737.02"],"Ask":[0,11,7,6,19,57,23,31,9,24,14,18,44],"Bid":[5,0,17,39,36,37,23,9,70,25,14,81,10],"symbol":"au2506","datetime":"2025-04-02 10:57:00","delta":-103.0,"close":736.88,"open":736.86,"high":737.02,"low":736.78,"volume":709,"dj":0,"dayma":735.5686046512,"delta累计":-47.0} +{"price":["736.48","736.5","736.52","736.54","736.56","736.58","736.6","736.62","736.64","736.66","736.68","736.7","736.72","736.74","736.76","736.78","736.8","736.82","736.86","736.88"],"Ask":[0,5,3,17,2,8,4,6,9,61,11,17,17,7,15,27,37,6,1,8],"Bid":[12,50,17,68,12,10,62,14,110,54,33,50,25,21,56,50,18,1,0,1],"symbol":"au2506","datetime":"2025-04-02 11:00:00","delta":-403.0,"close":736.48,"open":736.88,"high":736.88,"low":736.48,"volume":1015,"dj":0,"dayma":735.5790804598,"delta累计":-450.0} +{"price":["736.12","736.14","736.16","736.18","736.2","736.22","736.24","736.26","736.28","736.3","736.32","736.34","736.36","736.38","736.4","736.42","736.44","736.46","736.48","736.5","736.52","736.54","736.56","736.58","736.6","736.62","736.64"],"Ask":[0,9,24,13,56,0,39,20,13,26,45,42,40,44,40,0,17,17,51,79,16,29,89,205,78,27,0],"Bid":[21,30,31,118,33,28,0,44,22,72,40,1,87,29,42,64,43,34,86,53,28,59,4,50,5,12,3],"symbol":"au2506","datetime":"2025-04-02 11:03:00","delta":-20.0,"close":736.58,"open":736.5,"high":736.64,"low":736.12,"volume":2196,"dj":0,"dayma":735.5904545455,"delta累计":-470.0} +{"price":["736.5","736.52","736.54","736.56","736.58","736.6","736.62","736.64","736.66","736.68","736.7","736.72","736.74","736.76"],"Ask":[0,0,26,9,26,48,37,32,30,32,87,15,16,1],"Bid":[6,11,23,19,27,55,42,43,27,26,9,0,64,0],"symbol":"au2506","datetime":"2025-04-02 11:06:00","delta":7.0,"close":736.58,"open":736.56,"high":736.76,"low":736.5,"volume":772,"dj":0,"dayma":735.6015730337,"delta累计":-463.0} +{"price":["736.52","736.54","736.56","736.58","736.6","736.62","736.64","736.66","736.68","736.7","736.72","736.74","736.76","736.78","736.8","736.82","736.84","736.86","736.88","736.9","736.92","736.94","736.96","736.98","737.0","737.02","737.04","737.06","737.08","737.1","737.12","737.14","737.16"],"Ask":[0,0,11,29,26,5,14,2,7,24,6,12,7,5,7,16,24,11,11,8,14,67,23,87,66,26,6,50,5,31,34,8,2],"Bid":[3,16,4,166,13,0,5,0,1,16,4,4,3,0,30,17,1,0,0,5,42,68,30,20,15,17,16,13,22,21,49,6,0],"symbol":"au2506","datetime":"2025-04-02 11:09:00","delta":37.0,"close":737.0,"open":736.54,"high":737.16,"low":736.52,"volume":1341,"dj":1,"dayma":735.6171111111,"delta累计":-426.0} +{"price":["736.78","736.8","736.82","736.84","736.86","736.88","736.9","736.92","736.94","736.96","736.98","737.0","737.02","737.04","737.06","737.08","737.1","737.12","737.14"],"Ask":[13,15,37,29,22,3,35,49,14,27,36,1,21,24,26,0,2,11,19],"Bid":[50,52,55,20,15,9,57,16,95,41,20,64,15,45,35,2,3,0,4],"symbol":"au2506","datetime":"2025-04-02 11:12:00","delta":-214.0,"close":736.92,"open":737.02,"high":737.14,"low":736.78,"volume":1036,"dj":0,"dayma":735.6314285714,"delta累计":-640.0} +{"price":["736.88","736.9","736.92","736.94","736.96","736.98","737.0","737.02","737.04"],"Ask":[0,0,9,39,67,155,41,8,43],"Bid":[3,12,35,34,58,48,43,1,0],"symbol":"au2506","datetime":"2025-04-02 11:15:00","delta":128.0,"close":736.96,"open":736.96,"high":737.04,"low":736.88,"volume":615,"dj":0,"dayma":735.6458695652,"delta累计":-512.0} +{"price":["736.8","736.82","736.84","736.86","736.88","736.9","736.92","736.94","736.96","736.98","737.0"],"Ask":[0,9,9,36,62,67,21,25,6,10,6],"Bid":[17,54,43,30,41,16,12,10,20,27,0],"symbol":"au2506","datetime":"2025-04-02 11:18:00","delta":-19.0,"close":736.9,"open":736.98,"high":737.0,"low":736.8,"volume":542,"dj":0,"dayma":735.6593548387,"delta累计":-531.0} +{"price":["736.78","736.8","736.82","736.84","736.86","736.88","736.9","736.92","736.94","736.96","736.98","737.0"],"Ask":[0,9,13,33,31,35,23,43,30,18,16,38],"Bid":[18,14,46,53,64,38,28,9,3,23,5,0],"symbol":"au2506","datetime":"2025-04-02 11:21:00","delta":-12.0,"close":736.84,"open":736.9,"high":737.0,"low":736.78,"volume":635,"dj":0,"dayma":735.6719148936,"delta累计":-543.0} +{"price":["736.6","736.62","736.64","736.66","736.68","736.7","736.72","736.74","736.76","736.78","736.8","736.82","736.84","736.86"],"Ask":[3,7,15,66,27,31,25,0,5,6,5,8,7,2],"Bid":[23,73,13,94,17,48,8,12,28,18,27,11,7,0],"symbol":"au2506","datetime":"2025-04-02 11:24:00","delta":-172.0,"close":736.72,"open":736.82,"high":736.86,"low":736.6,"volume":660,"dj":-1,"dayma":735.6829473684,"delta累计":-715.0} +{"price":["736.64","736.66","736.68","736.7","736.72","736.74","736.76","736.78","736.8","736.82","736.84"],"Ask":[0,5,5,5,0,16,42,69,21,10,6],"Bid":[2,32,82,42,31,43,50,7,23,6,0],"symbol":"au2506","datetime":"2025-04-02 11:27:00","delta":-139.0,"close":736.76,"open":736.72,"high":736.84,"low":736.64,"volume":523,"dj":-1,"dayma":735.6941666667,"delta累计":-854.0} +{"price":["736.68","736.7","736.72","736.74","736.76","736.78","736.8","736.82"],"Ask":[0,13,74,153,24,49,57,26],"Bid":[19,130,146,76,31,28,19,0],"symbol":"au2506","datetime":"2025-04-02 11:30:00","delta":-53.0,"close":736.74,"open":736.76,"high":736.82,"low":736.68,"volume":891,"dj":0,"dayma":735.7049484536,"delta累计":-907.0} +{"price":["733.16","733.32","733.34","733.36","733.4","733.42","733.44","733.46","733.48","733.5","733.52","733.54","733.56","733.58","733.6","733.62","733.64","733.66","733.68","733.7","733.72","733.74","733.76","733.78","733.8","733.82","733.84","733.86","733.88","733.9","733.92","733.94","733.96","733.98","734.0","734.02","734.04","734.06","734.08","734.1","734.12","734.14","734.16"],"Ask":[0,89,56,154,19,59,81,140,77,27,83,201,51,75,69,61,63,219,111,484,295,138,211,44,87,39,0,0,76,17,108,93,56,62,385,51,514,155,146,55,123,91,101],"Bid":[49,126,0,80,37,0,105,56,0,170,49,212,24,21,80,0,305,213,183,166,0,59,57,0,729,0,169,93,43,91,33,45,256,177,238,141,90,34,56,68,133,91,0],"symbol":"au2506","datetime":"2025-04-02 13:33:00","delta":487.0,"close":733.76,"open":734.28,"high":734.28,"low":733.16,"volume":11344,"dj":0,"dayma":737.1121568627,"delta累计":401.0} +{"price":["732.48","732.52","732.56","732.58","732.6","732.62","732.64","732.66","732.68","732.7","732.72","732.74","732.78","732.82","732.86","732.88","732.9","732.92","732.94","732.96","732.98","733.0","733.02","733.04","733.06","733.08","733.1","733.12","733.14","733.16","733.18","733.2","733.22","733.24","733.26","733.28","733.3","733.32","733.34","733.36","733.38","733.58","733.64","733.72","733.74","733.76"],"Ask":[0,124,71,228,139,166,72,0,0,172,181,21,81,47,0,14,77,58,297,11,117,196,92,61,139,24,17,18,75,79,197,81,35,101,60,98,103,154,21,60,42,0,0,0,51,25],"Bid":[83,68,89,85,118,129,71,28,101,29,150,0,0,0,103,17,69,70,137,82,86,237,0,28,0,55,110,84,204,154,30,182,327,68,140,8,148,126,0,34,0,81,27,50,35,10],"symbol":"au2506","datetime":"2025-04-02 13:36:00","delta":-48.0,"close":732.92,"open":733.76,"high":733.76,"low":732.44,"volume":8686,"dj":1,"dayma":737.0315384615,"delta累计":353.0} +{"price":["732.86","732.88","732.9","732.92","732.96","732.98","733.0","733.02","733.04","733.06","733.08","733.1","733.12","733.14","733.16","733.18","733.2","733.22","733.24","733.26","733.28","733.3","733.32","733.38","733.4","733.42","733.46","733.5","733.52","733.56","733.62","733.64","733.66","733.68","733.7","733.72","733.74","733.76"],"Ask":[0,31,0,0,0,85,13,171,7,163,87,117,102,107,44,70,106,64,86,40,13,7,6,11,28,156,2,42,18,6,0,130,86,169,29,0,40,34],"Bid":[18,0,76,28,53,54,97,169,130,126,32,138,95,178,82,97,43,17,28,33,8,0,6,20,59,26,0,0,0,19,42,89,76,40,0,93,58,80],"symbol":"au2506","datetime":"2025-04-02 13:39:00","delta":-40.0,"close":733.68,"open":732.96,"high":733.76,"low":732.86,"volume":4468,"dj":1,"dayma":736.9683018868,"delta累计":313.0} +{"price":["733.34","733.36","733.38","733.4","733.42","733.44","733.46","733.48","733.5","733.52","733.54","733.56","733.58","733.6","733.62","733.64","733.66","733.68","733.7","733.72","733.74","733.76","733.78","733.8","733.82","733.84","733.86","733.88","733.9","733.92"],"Ask":[17,18,19,26,52,28,53,39,4,0,36,12,4,40,43,16,7,46,80,156,98,27,8,51,5,78,94,124,95,29],"Bid":[19,30,48,52,87,13,36,27,35,3,0,13,60,44,15,54,72,133,28,67,23,56,30,100,35,92,171,80,13,0],"symbol":"au2506","datetime":"2025-04-02 13:42:00","delta":-131.0,"close":733.86,"open":733.68,"high":733.92,"low":733.34,"volume":2862,"dj":0,"dayma":736.9107407407,"delta累计":182.0} +{"price":["733.78","733.8","733.82","733.84","733.86","733.88","733.9","733.92","733.96","733.98","734.0","734.02","734.06","734.08","734.1","734.12","734.14","734.16","734.18","734.2","734.22","734.24","734.26"],"Ask":[0,50,64,140,6,87,48,112,8,9,24,0,0,103,44,12,64,43,148,77,132,36,21],"Bid":[10,37,69,47,158,99,28,30,0,0,0,31,23,41,80,40,42,58,120,160,0,14,0],"symbol":"au2506","datetime":"2025-04-02 13:45:00","delta":141.0,"close":734.08,"open":733.88,"high":734.26,"low":733.78,"volume":2489,"dj":0,"dayma":736.8592727273,"delta累计":323.0} +{"price":["733.8","733.82","733.84","733.86","733.88","733.9","733.92","733.94","733.96","733.98","734.0","734.02","734.04","734.06","734.08","734.1","734.12","734.14","734.16","734.18","734.2","734.22","734.26","734.28","734.3","734.32","734.34","734.36","734.38"],"Ask":[0,15,12,12,20,73,30,89,46,21,29,102,28,34,27,31,10,29,17,10,0,25,24,16,107,3,93,151,12],"Bid":[16,126,46,7,33,22,37,55,31,31,119,51,25,29,9,0,31,9,0,0,31,0,57,24,83,16,37,76,0],"symbol":"au2506","datetime":"2025-04-02 13:48:00","delta":65.0,"close":734.3,"open":734.08,"high":734.38,"low":733.8,"volume":2283,"dj":0,"dayma":736.8135714286,"delta累计":388.0} +{"price":["734.26","734.28","734.3","734.32","734.34","734.36","734.38","734.4","734.42","734.44","734.46","734.48","734.5","734.52","734.54","734.56","734.58","734.6","734.62","734.64","734.66","734.68","734.7","734.72","734.74","734.76"],"Ask":[12,14,3,41,23,73,6,89,46,95,0,70,78,60,58,85,51,70,34,5,20,0,32,24,27,15],"Bid":[17,26,27,16,107,27,13,86,25,17,81,76,97,62,38,36,77,68,0,13,7,19,25,58,4,0],"symbol":"au2506","datetime":"2025-04-02 13:51:00","delta":9.0,"close":734.7,"open":734.32,"high":734.76,"low":734.26,"volume":2295,"dj":0,"dayma":736.7764912281,"delta累计":397.0} +{"price":["734.46","734.5","734.52","734.54","734.56","734.58","734.6","734.62","734.64","734.66","734.68","734.7","734.72","734.74","734.76","734.78","734.8","734.82"],"Ask":[0,23,1,31,7,53,42,18,116,87,78,90,102,88,48,23,94,24],"Bid":[32,41,36,16,4,33,113,68,46,93,71,59,96,76,71,43,15,0],"symbol":"au2506","datetime":"2025-04-02 13:54:00","delta":12.0,"close":734.6,"open":734.68,"high":734.82,"low":734.46,"volume":1951,"dj":0,"dayma":736.7389655172,"delta累计":409.0} +{"price":["734.28","734.3","734.32","734.34","734.36","734.38","734.4","734.42","734.44","734.46","734.48","734.5","734.52","734.54","734.56","734.58","734.6","734.62","734.64","734.66","734.68","734.7","734.72","734.74","734.76","734.78","734.8","734.82","734.84","734.86","734.88","734.9","734.92","734.94"],"Ask":[0,9,17,22,29,0,23,0,9,15,26,55,45,0,5,12,51,54,26,19,29,71,0,25,3,7,33,8,14,21,32,0,28,55],"Bid":[30,0,62,0,30,14,26,32,22,73,76,36,92,2,161,30,37,41,3,13,20,21,35,6,17,37,10,30,5,21,28,75,71,0],"symbol":"au2506","datetime":"2025-04-02 13:57:00","delta":-413.0,"close":734.28,"open":734.58,"high":734.94,"low":734.28,"volume":2085,"dj":0,"dayma":736.6972881356,"delta累计":-4.0} +{"price":["734.24","734.3","734.34","734.36","734.38","734.4","734.42","734.44","734.46","734.48","734.5","734.52","734.54","734.56","734.58","734.6","734.62","734.64","734.66","734.68","734.7","734.72","734.74"],"Ask":[0,3,14,40,13,96,44,44,20,10,8,16,21,82,70,91,33,28,12,0,0,23,6],"Bid":[21,0,0,21,42,46,19,0,0,0,3,28,30,67,122,34,20,13,13,7,13,10,0],"symbol":"au2506","datetime":"2025-04-02 14:00:00","delta":165.0,"close":734.7,"open":734.3,"high":734.74,"low":734.24,"volume":1274,"dj":2,"dayma":736.6294117647,"delta累计":521.0} +{"price":["734.52","734.58","734.6","734.64","734.66","734.68","734.7","734.72","734.74","734.76","734.78","734.8","734.82"],"Ask":[0,0,16,15,50,53,52,117,78,62,38,93,45],"Bid":[16,13,2,33,73,34,100,18,79,63,52,100,18],"symbol":"au2506","datetime":"2025-04-02 14:03:00","delta":18.0,"close":734.76,"open":734.74,"high":734.82,"low":734.52,"volume":1321,"dj":0,"dayma":736.5934615385,"delta累计":539.0} +{"price":["734.42","734.44","734.46","734.48","734.5","734.52","734.54","734.56","734.58","734.6","734.62","734.64","734.66","734.7","734.72","734.74","734.76","734.78","734.8"],"Ask":[0,0,18,39,38,78,56,15,18,41,19,22,30,0,0,28,0,4,10],"Bid":[36,72,106,137,137,36,19,31,4,57,47,12,25,31,16,1,35,0,0],"symbol":"au2506","datetime":"2025-04-02 14:06:00","delta":-386.0,"close":734.44,"open":734.76,"high":734.8,"low":734.42,"volume":1371,"dj":0,"dayma":736.5528301887,"delta累计":153.0} +{"price":["733.62","733.64","733.66","733.68","733.7","733.72","733.74","733.78","733.8","733.82","733.84","733.86","733.88","733.9","733.92","733.94","733.96","734.0","734.02","734.04","734.06","734.08","734.12","734.14","734.16","734.2","734.22","734.24","734.28","734.3","734.32","734.34","734.36","734.38","734.4","734.42","734.44","734.46","734.48","734.5","734.52","734.54","734.56","734.58","734.6","734.62","734.64","734.66"],"Ask":[0,0,60,22,84,16,55,16,24,20,5,9,64,56,18,83,104,0,6,0,18,39,28,21,6,84,0,0,8,13,0,3,2,0,22,0,0,9,6,16,11,19,20,0,39,12,28,10],"Bid":[8,59,22,30,15,18,112,9,23,31,31,86,153,111,24,52,0,118,26,22,71,0,0,3,0,35,25,33,3,47,13,7,30,15,21,5,17,7,7,17,44,8,34,5,14,28,2,0],"symbol":"au2506","datetime":"2025-04-02 14:09:00","delta":-385.0,"close":733.68,"open":734.44,"high":734.66,"low":733.62,"volume":2884,"dj":-3,"dayma":736.4996296296,"delta累计":-232.0} +{"price":["733.3","733.32","733.34","733.36","733.38","733.4","733.42","733.46","733.5","733.52","733.54","733.56","733.58","733.6","733.62","733.64","733.66","733.68","733.7","733.72","733.74","733.76","733.78","733.8","733.82","733.84","733.86","733.88","733.9","733.92","733.94"],"Ask":[0,36,6,2,42,20,0,0,28,0,12,49,32,2,11,8,18,48,61,47,79,63,49,90,40,10,56,12,63,8,16],"Bid":[92,0,22,60,9,23,11,12,113,20,26,16,16,43,44,26,0,15,76,24,74,27,47,15,47,45,28,72,43,3,0],"symbol":"au2506","datetime":"2025-04-02 14:12:00","delta":-141.0,"close":733.32,"open":733.68,"high":733.94,"low":733.3,"volume":2176,"dj":-1,"dayma":736.4418181818,"delta累计":-373.0} +{"price":["733.06","733.08","733.1","733.12","733.14","733.16","733.18","733.2","733.22","733.24","733.26","733.3","733.32","733.36","733.38","733.4","733.42","733.44","733.46","733.48","733.5","733.52","733.54","733.56","733.58"],"Ask":[0,0,73,14,36,62,342,76,62,70,5,5,14,27,10,11,82,30,88,72,171,19,64,63,15],"Bid":[5,9,96,85,105,93,112,34,9,6,16,14,44,0,9,30,83,32,46,114,105,8,16,24,0],"symbol":"au2506","datetime":"2025-04-02 14:15:00","delta":316.0,"close":733.54,"open":733.36,"high":733.58,"low":733.06,"volume":2910,"dj":0,"dayma":736.39,"delta累计":-57.0} +{"price":["733.5","733.52","733.54","733.56","733.58","733.6","733.62","733.64","733.66","733.68","733.7","733.72","733.74","733.76","733.78","733.8","733.82","733.84","733.86"],"Ask":[5,5,12,12,1,45,6,13,1,82,48,46,70,63,67,107,42,54,121],"Bid":[6,4,9,2,11,12,18,4,9,22,64,51,48,85,28,70,49,69,21],"symbol":"au2506","datetime":"2025-04-02 14:18:00","delta":218.0,"close":733.84,"open":733.52,"high":733.86,"low":733.5,"volume":1510,"dj":0,"dayma":736.3452631579,"delta累计":161.0} +{"price":["733.78","733.8","733.82","733.84","733.86","733.88","733.9","733.92","733.94","733.96","733.98","734.0","734.02","734.04","734.06","734.08","734.1","734.12","734.14","734.16","734.18","734.2","734.22","734.24","734.26","734.28","734.3","734.32","734.34","734.36","734.38"],"Ask":[5,0,31,5,50,72,48,25,38,34,60,98,42,73,34,9,0,26,36,17,11,33,13,55,64,42,12,0,6,23,57],"Bid":[27,13,25,8,41,51,55,17,3,63,26,41,23,24,0,0,3,7,26,47,22,69,69,69,36,0,62,16,0,0,14],"symbol":"au2506","datetime":"2025-04-02 14:21:00","delta":162.0,"close":734.2,"open":733.88,"high":734.38,"low":733.78,"volume":1960,"dj":0,"dayma":736.3082758621,"delta累计":323.0} +{"price":["733.58","733.6","733.62","733.64","733.66","733.68","733.7","733.72","733.74","733.76","733.78","733.8","733.82","733.84","733.86","733.88","733.9","733.92","733.94","733.96","733.98","734.0","734.02","734.04","734.06","734.08","734.12","734.16","734.18","734.2","734.22","734.24"],"Ask":[0,5,74,54,1,12,23,71,70,53,38,24,0,6,75,29,46,20,47,116,14,0,10,3,0,11,0,0,0,0,0,4],"Bid":[11,11,89,64,17,0,38,66,39,17,50,24,10,0,61,60,55,35,13,32,6,19,45,4,14,11,16,7,9,5,7,0],"symbol":"au2506","datetime":"2025-04-02 14:24:00","delta":-29.0,"close":733.9,"open":734.2,"high":734.24,"low":733.58,"volume":1741,"dj":-3,"dayma":736.2674576271,"delta累计":294.0} +{"price":["733.76","733.78","733.8","733.82","733.84","733.86","733.88","733.9","733.92","733.94","733.96","733.98","734.0","734.02","734.04","734.06"],"Ask":[11,9,27,30,46,19,32,59,26,59,25,1,28,39,17,53],"Bid":[10,12,87,31,28,36,90,70,29,34,19,6,19,20,5,28],"symbol":"au2506","datetime":"2025-04-02 14:27:00","delta":-43.0,"close":733.8,"open":733.9,"high":734.06,"low":733.76,"volume":1097,"dj":0,"dayma":736.2263333333,"delta累计":251.0} +{"price":["733.6","733.62","733.64","733.66","733.68","733.7","733.72","733.74","733.76","733.78","733.8","733.82","733.84","733.86","733.88","733.9","733.92","733.96","734.0","734.02","734.04","734.06","734.08","734.1","734.12","734.14","734.16","734.18","734.2","734.22","734.24","734.26","734.28","734.3"],"Ask":[13,0,21,17,8,0,32,4,9,20,37,22,29,41,7,106,46,0,68,54,14,22,0,90,32,29,21,3,81,17,12,17,20,46],"Bid":[42,18,23,14,17,47,10,13,42,28,98,47,22,97,3,57,0,3,59,102,37,4,41,55,75,57,3,19,86,34,4,0,0,0],"symbol":"au2506","datetime":"2025-04-02 14:30:00","delta":-219.0,"close":734.22,"open":733.78,"high":734.3,"low":733.6,"volume":2261,"dj":1,"dayma":736.193442623,"delta累计":32.0} +{"price":["733.66","733.68","733.7","733.72","733.74","733.76","733.78","733.8","733.82","733.84","733.86","733.88","733.9","733.92","733.94","733.96","734.0","734.02","734.06","734.08","734.1","734.12","734.14","734.16","734.18","734.2","734.22","734.24"],"Ask":[0,28,37,89,22,48,43,27,2,16,29,16,22,15,0,14,0,0,3,5,13,0,30,43,43,45,19,7],"Bid":[20,69,16,44,13,64,1,33,19,14,29,37,8,11,6,12,11,14,30,5,50,21,54,83,94,24,10,0],"symbol":"au2506","datetime":"2025-04-02 14:33:00","delta":-176.0,"close":733.9,"open":734.24,"high":734.24,"low":733.66,"volume":1527,"dj":-2,"dayma":736.1564516129,"delta累计":-144.0} +{"price":["733.82","733.84","733.86","733.88","733.9","733.92","733.94","733.96","733.98","734.0","734.02","734.04"],"Ask":[0,0,43,43,66,33,31,57,95,18,4,22],"Bid":[8,18,77,68,38,47,54,49,70,8,6,0],"symbol":"au2506","datetime":"2025-04-02 14:36:00","delta":-31.0,"close":733.94,"open":733.92,"high":734.04,"low":733.82,"volume":925,"dj":0,"dayma":736.1212698413,"delta累计":-175.0} +{"price":["733.9","733.92","733.94","733.96","733.98","734.0","734.02","734.04","734.06","734.08","734.1","734.12","734.14","734.16","734.18","734.2","734.22","734.24","734.26"],"Ask":[0,6,25,21,0,29,61,42,76,55,19,44,9,70,9,17,33,36,22],"Bid":[23,31,12,29,14,47,63,28,45,25,47,34,40,65,7,23,36,5,0],"symbol":"au2506","datetime":"2025-04-02 14:39:00","delta":0.0,"close":734.26,"open":733.92,"high":734.26,"low":733.9,"volume":1241,"dj":0,"dayma":736.0921875,"delta累计":-175.0} +{"price":["734.06","734.08","734.1","734.12","734.14","734.16","734.18","734.2","734.22","734.24","734.26","734.28"],"Ask":[1,11,84,49,30,29,19,12,84,10,15,10],"Bid":[27,75,83,15,50,38,73,102,58,15,2,0],"symbol":"au2506","datetime":"2025-04-02 14:42:00","delta":-184.0,"close":734.12,"open":734.24,"high":734.28,"low":734.06,"volume":1036,"dj":0,"dayma":736.0618461538,"delta累计":-359.0} +{"price":["734.06","734.08","734.1","734.12","734.14","734.16","734.18","734.2","734.22","734.24","734.26","734.28","734.3","734.32","734.34","734.4","734.42","734.44","734.46","734.48","734.5","734.52","734.54","734.56"],"Ask":[0,0,18,14,22,31,37,106,31,29,52,40,47,14,12,42,0,68,32,52,82,0,9,9],"Bid":[1,30,48,17,15,32,81,51,64,40,24,28,9,16,6,31,108,19,43,2,9,29,11,18],"symbol":"au2506","datetime":"2025-04-02 14:45:00","delta":15.0,"close":734.48,"open":734.12,"high":734.56,"low":734.06,"volume":1643,"dj":0,"dayma":736.0378787879,"delta累计":-344.0} +{"price":["734.18","734.2","734.22","734.24","734.26","734.28","734.3","734.32","734.34","734.36","734.38","734.4","734.42","734.44","734.46","734.48","734.5","734.52","734.54","734.56","734.58"],"Ask":[2,0,52,0,4,27,28,8,75,40,45,34,5,18,14,15,15,7,28,43,10],"Bid":[26,24,20,32,4,83,52,89,59,47,50,44,5,26,4,5,24,40,24,25,0],"symbol":"au2506","datetime":"2025-04-02 14:48:00","delta":-213.0,"close":734.3,"open":734.48,"high":734.58,"low":734.18,"volume":1225,"dj":0,"dayma":736.0119402985,"delta累计":-557.0} +{"price":["734.1","734.12","734.14","734.16","734.18","734.2","734.22","734.24","734.26","734.28","734.3","734.32","734.34","734.36","734.38"],"Ask":[0,11,3,0,1,40,58,96,126,27,82,78,33,13,12],"Bid":[8,27,50,64,43,94,48,86,49,20,10,32,45,5,0],"symbol":"au2506","datetime":"2025-04-02 14:51:00","delta":-1.0,"close":734.2,"open":734.26,"high":734.38,"low":734.1,"volume":1229,"dj":-1,"dayma":735.9852941176,"delta累计":-558.0} +{"price":["734.04","734.06","734.08","734.1","734.12","734.14","734.16","734.18","734.22","734.24","734.26","734.28","734.3","734.32","734.34","734.36","734.38"],"Ask":[0,0,35,28,64,28,34,8,0,8,12,31,111,50,93,35,7],"Bid":[19,1,37,66,38,11,36,33,34,38,27,54,51,35,13,3,0],"symbol":"au2506","datetime":"2025-04-02 14:54:00","delta":48.0,"close":734.08,"open":734.26,"high":734.38,"low":734.04,"volume":1147,"dj":-2,"dayma":735.9576811594,"delta累计":-510.0} +{"price":["733.82","733.84","733.86","733.88","733.9","733.92","733.94","733.96","733.98","734.0","734.02","734.04","734.06","734.08","734.1","734.12","734.14"],"Ask":[0,2,15,28,79,65,102,133,42,43,12,17,27,13,8,24,18],"Bid":[7,35,80,84,147,69,84,32,11,57,29,36,49,28,25,1,0],"symbol":"au2506","datetime":"2025-04-02 14:57:00","delta":-146.0,"close":733.92,"open":734.04,"high":734.14,"low":733.82,"volume":1559,"dj":0,"dayma":735.9285714286,"delta累计":-656.0} +{"price":["733.58","733.6","733.62","733.64","733.66","733.68","733.7","733.72","733.74","733.76","733.78","733.8","733.82","733.84","733.86","733.88","733.9","733.92"],"Ask":[0,0,13,79,222,307,313,71,91,52,40,26,70,19,20,10,3,7],"Bid":[34,32,82,161,253,163,100,92,23,62,9,18,32,7,2,18,5,0],"symbol":"au2506","datetime":"2025-04-02 15:00:00","delta":250.0,"close":733.62,"open":733.92,"high":733.92,"low":733.58,"volume":2660,"dj":0,"dayma":735.896056338,"delta累计":-406.0} diff --git a/1.交易策略/999.其他策略/4.松鼠SF20_基于LLM的订单流日内交易策略/使用文档/4.02版本_new/traderdata/au2506_stops.json b/1.交易策略/999.其他策略/4.松鼠SF20_基于LLM的订单流日内交易策略/使用文档/4.02版本_new/traderdata/au2506_stops.json new file mode 100644 index 0000000..38c0c61 --- /dev/null +++ b/1.交易策略/999.其他策略/4.松鼠SF20_基于LLM的订单流日内交易策略/使用文档/4.02版本_new/traderdata/au2506_stops.json @@ -0,0 +1,16 @@ +{ + "long": { + "position": 0, + "entry_price": 0, + "stop_loss": 0, + "take_profit": 0, + "trailing_stop": 0 + }, + "short": { + "position": 0, + "entry_price": 0, + "stop_loss": 0, + "take_profit": 0, + "trailing_stop": 0 + } +} \ No newline at end of file diff --git a/1.交易策略/999.其他策略/4.松鼠SF20_基于LLM的订单流日内交易策略/使用文档/4.02版本_new/traderdata/au2506traderdata.csv b/1.交易策略/999.其他策略/4.松鼠SF20_基于LLM的订单流日内交易策略/使用文档/4.02版本_new/traderdata/au2506traderdata.csv new file mode 100644 index 0000000..7fcaeeb --- /dev/null +++ b/1.交易策略/999.其他策略/4.松鼠SF20_基于LLM的订单流日内交易策略/使用文档/4.02版本_new/traderdata/au2506traderdata.csv @@ -0,0 +1,2 @@ +datetime,pos,short_trailing_stop_price,long_trailing_stop_price,sl_long_price,sl_shor_price +2025-04-02 14:44:09,0,0,0,0,0 diff --git a/1.交易策略/999.其他策略/4.松鼠SF20_基于LLM的订单流日内交易策略/使用文档/4.02版本_new/专享策略20_o3mini.py b/1.交易策略/999.其他策略/4.松鼠SF20_基于LLM的订单流日内交易策略/使用文档/4.02版本_new/专享策略20_o3mini.py new file mode 100644 index 0000000..e441b41 --- /dev/null +++ b/1.交易策略/999.其他策略/4.松鼠SF20_基于LLM的订单流日内交易策略/使用文档/4.02版本_new/专享策略20_o3mini.py @@ -0,0 +1,2610 @@ +''' +#公众号:松鼠Quant +#主页:www.quant789.com +#本策略仅作学习交流使用,实盘交易盈亏投资者个人负责!!! +#版权归松鼠Quant所有,禁止转发、转卖源码违者必究。 + +该代码的主要目的是处理Tick数据并生成交易信号。代码中定义了一个tickcome函数,它接收到Tick数据后会进行一系列的处理,包括构建Tick字典、更新上一个Tick的成交量、保存Tick数据、生成K线数据等。其中涉及到的一些函数有: + +on_tick(tick): 处理单个Tick数据,根据Tick数据生成K线数据。 +tickdata(df, symbol): 处理Tick数据,生成K线数据。 +orderflow_df_new(df_tick, df_min, symbol): 处理Tick和K线数据,生成订单流数据。 +GetOrderFlow_dj(kData): 计算订单流的信号指标。 +除此之外,代码中还定义了一个MyTrader类,继承自TraderApiBase,用于实现交易相关的功能。 +#公众号:松鼠Quant +#主页:www.quant789.com +#本策略仅作学习交流使用,实盘交易盈亏投资者个人负责!!! +#版权归松鼠Quant所有,禁止转发、转卖源码违者必究。 +''' +from multiprocessing import Process, Queue +from AlgoPlus.CTP.MdApi import run_tick_engine +from AlgoPlus.CTP.FutureAccount import get_simulate_account +from AlgoPlus.CTP.FutureAccount import FutureAccount +from AlgoPlus.CTP.TraderApiBase import TraderApiBase +from AlgoPlus.ta.time_bar import tick_to_bar +import pandas as pd +from datetime import datetime, timedelta +from datetime import time as s_time +import operator +import time +import numpy as np +import os +import re +import json +import requests # 添加requests库用于API调用 +from openai import OpenAI # 导入OpenAI客户端 +import threading +from queue import Queue as ThreadQueue +import warnings +warnings.filterwarnings("ignore", category=FutureWarning) +import copy +import math +import shutil +import re # 新增 +import logging # 新增 +from logging.handlers import RotatingFileHandler # 新增 + +# 在文件顶部定义全局变量 +tickdatadict = {} # 存储Tick数据的字典 +quotedict = {} # 存储行情数据的字典 +ofdatadict = {} # 存储K线数据的字典 +trader_df = pd.DataFrame({}) # 存储交易数据的DataFrame对象 +previous_volume = {} # 上一个Tick的成交量 +tsymbollist={} +# 全局LLM配置变量 +GLOBAL_LLM_CONFIG = {} # 全局大模型配置参数 +# 全局交易信号队列,用于存储AI模型生成的交易信号 +AI_SIGNAL_QUEUE = ThreadQueue() +# 标记是否有AI线程正在运行 +AI_THREAD_RUNNING = False +# 不再需要单独的K线时间粒度全局变量,它已经被整合到GLOBAL_LLM_CONFIG中 + +# 设置日志系统 +def setup_logging(log_folder='logs'): + # 确保日志文件夹存在 + if not os.path.exists(log_folder): + os.makedirs(log_folder) + + # 创建日志格式 + formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s') + + # 设置AI分析日志 + ai_logger = logging.getLogger('ai_analysis') + ai_logger.setLevel(logging.INFO) + + # 设置带有文件循环的文件处理器 + ai_file_handler = RotatingFileHandler( + os.path.join(log_folder, 'ai_analysis.log'), + maxBytes=10*1024*1024, # 10MB + backupCount=5 + ) + ai_file_handler.setFormatter(formatter) + ai_logger.addHandler(ai_file_handler) + + # 设置交易信号日志 + signal_logger = logging.getLogger('trading_signals') + signal_logger.setLevel(logging.INFO) + + signal_file_handler = RotatingFileHandler( + os.path.join(log_folder, 'trading_signals.log'), + maxBytes=10*1024*1024, # 10MB + backupCount=5 + ) + signal_file_handler.setFormatter(formatter) + signal_logger.addHandler(signal_file_handler) + + # 设置止损止盈日志 + stoploss_logger = logging.getLogger('stoploss') + stoploss_logger.setLevel(logging.INFO) + + stoploss_file_handler = RotatingFileHandler( + os.path.join(log_folder, 'stoploss.log'), + maxBytes=10*1024*1024, # 10MB + backupCount=5 + ) + stoploss_file_handler.setFormatter(formatter) + stoploss_logger.addHandler(stoploss_file_handler) + + # 返回三个日志记录器 + return ai_logger, signal_logger, stoploss_logger + +# 全局日志记录器 +AI_LOGGER, SIGNAL_LOGGER, STOPLOSS_LOGGER = setup_logging() + +def tickcome(md_queue): + global previous_volume + + data=md_queue + instrument_id = data['InstrumentID'].decode() # 品种代码 + ActionDay = data['ActionDay'].decode() # 交易日日期 + update_time = data['UpdateTime'].decode() # 更新时间 + #zzg_quant + update_millisec = str(data['UpdateMillisec']) # 更新毫秒数 + created_at = ActionDay[:4] + '-' + ActionDay[4:6] + '-' + ActionDay[6:] + ' ' + update_time + '.' + update_millisec #创建时间 + # 构建tick字典 + tick = { + 'symbol': instrument_id, # 品种代码和交易所ID + 'created_at':datetime.strptime(created_at, "%Y-%m-%d %H:%M:%S.%f"), + #'created_at': created_at, # 创建时间 + 'price': float(data['LastPrice']), # 最新价 + 'last_volume': int(data['Volume']) - previous_volume.get(instrument_id, 0) if previous_volume.get(instrument_id, 0) != 0 else 0, # 瞬时成交量 + 'bid_p': float(data['BidPrice1']), # 买价 + 'bid_v': int(data['BidVolume1']), # 买量 + 'ask_p': float(data['AskPrice1']), # 卖价 + 'ask_v': int(data['AskVolume1']), # 卖量 + 'UpperLimitPrice': float(data['UpperLimitPrice']), # 涨停价 + 'LowerLimitPrice': float(data['LowerLimitPrice']), # 跌停价 + 'TradingDay': data['TradingDay'].decode(), # 交易日日期 + 'cum_volume': int(data['Volume']), # 最新总成交量 + 'cum_amount': float(data['Turnover']), # 最新总成交额 + 'cum_position': int(data['OpenInterest']), # 合约持仓量 + } + # 更新上一个Tick的成交量 + previous_volume[instrument_id] = int(data['Volume']) + if tick['last_volume']>0: + #print(tick['created_at'],'vol:',tick['last_volume']) + # 处理Tick数据 + on_tick(tick) + + +def can_time(hour, minute): + hour = str(hour) + minute = str(minute) + if len(minute) == 1: + minute = "0" + minute + return int(hour + minute) + +def on_tick(tick): + + tm=can_time(tick['created_at'].hour,tick['created_at'].minute) + #print(tick['symbol']) + #print(1) + #if tm>1500 and tm<2100 : + # return + if tick['last_volume']==0: + return + quotes = tick + timetick=str(tick['created_at']).replace('+08:00', '') + tsymbol=tick['symbol'] + if tsymbol not in tsymbollist.keys(): + # 获取tick的买卖价和买卖量 + #zzg_quant + tsymbollist[tsymbol]=tick + bid_p=quotes['bid_p'] + ask_p=quotes['ask_p'] + bid_v=quotes['bid_v'] + ask_v=quotes['ask_v'] + else: + # 获取上一个tick的买卖价和买卖量 + rquotes =tsymbollist[tsymbol] + bid_p=rquotes['bid_p'] + ask_p=rquotes['ask_p'] + bid_v=rquotes['bid_v'] + ask_v=rquotes['ask_v'] + tsymbollist[tsymbol]=tick + tick_dt=pd.DataFrame({'datetime':timetick,'symbol':tick['symbol'],'mainsym':tick['symbol'].rstrip('0123456789').upper(),'lastprice':tick['price'], + 'vol':tick['last_volume'], + 'bid_p':bid_p,'ask_p':ask_p,'bid_v':bid_v,'ask_v':ask_v},index=[0]) + sym = tick_dt['symbol'][0] + #print(tick_dt) + + # 直接调用tickdata,不传递resample_rule参数,让其自行从全局配置获取 + tickdata(tick_dt, sym) + +#公众号:松鼠Quant +#主页:www.quant789.com +#本策略仅作学习交流使用,实盘交易盈亏投资者个人负责!!! +#版权归松鼠Quant所有,禁止转发、转卖源码违者必究。 + +def data_of(df): + global trader_df + # 将df数据合并到trader_df中 + trader_df = pd.concat([trader_df, df], ignore_index=True) + #print('trader_df: ', len(trader_df)) + #print(trader_df) + +def process(bidDict, askDict, symbol): + try: + # 尝试从quotedict中获取对应品种的报价数据 + dic = quotedict[symbol] + bidDictResult = dic['bidDictResult'] + askDictResult = dic['askDictResult'] + except: + # 如果获取失败,则初始化bidDictResult和askDictResult为空字典 + bidDictResult, askDictResult = {}, {} + + # 将所有买盘字典和卖盘字典的key合并,并按升序排序 + sList = sorted(set(list(bidDict.keys()) + list(askDict.keys()))) + + # 遍历所有的key,将相同key的值进行累加 + for s in sList: + if s in bidDict: + if s in bidDictResult: + bidDictResult[s] = int(bidDict[s]) + bidDictResult[s] + else: + bidDictResult[s] = int(bidDict[s]) + if s not in askDictResult: + askDictResult[s] = 0 + else: + if s in askDictResult: + askDictResult[s] = int(askDict[s]) + askDictResult[s] + else: + askDictResult[s] = int(askDict[s]) + if s not in bidDictResult: + bidDictResult[s] = 0 + + # 构建包含bidDictResult和askDictResult的字典,并存入quotedict中 + df = {'bidDictResult': bidDictResult, 'askDictResult': askDictResult} + quotedict[symbol] = df + + return bidDictResult, askDictResult +#公众号:松鼠Quant +#主页:www.quant789.com +#本策略仅作学习交流使用,实盘交易盈亏投资者个人负责!!! +#版权归松鼠Quant所有,禁止转发、转卖源码违者必究。 + + +def tickdata(df, symbol): + tickdata =pd.DataFrame({'datetime':df['datetime'],'symbol':df['symbol'],'lastprice':df['lastprice'], + 'volume':df['vol'],'bid_p':df['bid_p'],'bid_v':df['bid_v'],'ask_p':df['ask_p'],'ask_v':df['ask_v']}) + try: + if symbol in tickdatadict.keys(): + rdf=tickdatadict[symbol] + rdftm=pd.to_datetime(rdf['bartime'][0]).strftime('%Y-%m-%d %H:%M:%S') + now=str(tickdata['datetime'][0]) + if now>rdftm: + try: + oo=ofdatadict[symbol] + data_of(oo) + #print('oo',oo) + if symbol in quotedict.keys(): + quotedict.pop(symbol) + if symbol in tickdatadict.keys(): + tickdatadict.pop(symbol) + if symbol in ofdatadict.keys(): + ofdatadict.pop(symbol) + except IOError as e: + print('rdftm捕获到异常',e) + tickdata['bartime'] = pd.to_datetime(tickdata['datetime']) + tickdata['open'] = tickdata['lastprice'] + tickdata['high'] = tickdata['lastprice'] + tickdata['low'] = tickdata['lastprice'] + tickdata['close'] = tickdata['lastprice'] + tickdata['starttime'] = tickdata['datetime'] + else: + tickdata['bartime'] = rdf['bartime'] + tickdata['open'] = rdf['open'] + tickdata['high'] = max(tickdata['lastprice'].values,rdf['high'].values) + tickdata['low'] = min(tickdata['lastprice'].values,rdf['low'].values) + tickdata['close'] = tickdata['lastprice'] + tickdata['volume']=df['vol']+rdf['volume'].values + tickdata['starttime'] = rdf['starttime'] + else : + print('新bar的第一个tick进入') + tickdata['bartime'] = pd.to_datetime(tickdata['datetime']) + tickdata['open'] = tickdata['lastprice'] + tickdata['high'] = tickdata['lastprice'] + tickdata['low'] = tickdata['lastprice'] + tickdata['close'] = tickdata['lastprice'] + tickdata['starttime'] = tickdata['datetime'] + except IOError as e: + print('捕获到异常',e) + + + tickdata['bartime'] = pd.to_datetime(tickdata['bartime']) + # 直接从全局配置获取resample_rule + resample_rule = GLOBAL_LLM_CONFIG.get('bar_resample_rule') + + # 使用resample_rule生成K线 + bardata = tickdata.resample(on = 'bartime', rule = resample_rule, label = 'right', closed = 'right').agg({'starttime':'first','symbol':'last','open':'first','high':'max','low':'min','close':'last','volume':'sum'}).reset_index(drop = False) + bardata =bardata.dropna().reset_index(drop = True) + bardata['bartime'] = pd.to_datetime(bardata['bartime'][0]).strftime('%Y-%m-%d %H:%M:%S') + tickdatadict[symbol]=bardata + tickdata['volume']=df['vol'].values + #print(bardata['symbol'].values,bardata['bartime'].values) + orderflow_df_new(tickdata,bardata,symbol) + # time.sleep(0.5) + +#公众号:松鼠Quant +#主页:www.quant789.com +#本策略仅作学习交流使用,实盘交易盈亏投资者个人负责!!! +#版权归松鼠Quant所有,禁止转发、转卖源码违者必究。 + +def orderflow_df_new(df_tick,df_min,symbol): + startArray = pd.to_datetime(df_min['starttime']).values + voluememin= df_min['volume'].values + highs=df_min['high'].values + lows=df_min['low'].values + opens=df_min['open'].values + closes=df_min['close'].values + #endArray = pd.to_datetime(df_min['bartime']).values + endArray = df_min['bartime'].values + #print(endArray) + deltaArray = np.zeros((len(endArray),)) + tTickArray = pd.to_datetime(df_tick['datetime']).values + bp1TickArray = df_tick['bid_p'].values + ap1TickArray = df_tick['ask_p'].values + lastTickArray = df_tick['lastprice'].values + volumeTickArray = df_tick['volume'].values + symbolarray = df_tick['symbol'].values + indexFinal = 0 + for index,tEnd in enumerate(endArray): + dt=endArray[index] + start = startArray[index] + bidDict = {} + askDict = {} + bar_vol=voluememin[index] + bar_close=closes[index] + bar_open=opens[index] + bar_low=lows[index] + bar_high=highs[index] + bar_symbol=symbolarray[index] + # for indexTick in range(indexFinal,len(df_tick)): + # if tTickArray[indexTick] >= tEnd: + # break + # elif (tTickArray[indexTick] >= start) & (tTickArray[indexTick] < tEnd): + Bp = round(bp1TickArray[0],4) + Ap = round(ap1TickArray[0],4) + LastPrice = round(lastTickArray[0],4) + Volume = volumeTickArray[0] + if LastPrice >= Ap: + if str(LastPrice) in askDict.keys(): + askDict[str(LastPrice)] += Volume + else: + askDict[str(LastPrice)] = Volume + if LastPrice <= Bp: + if str(LastPrice) in bidDict.keys(): + bidDict[str(LastPrice)] += Volume + else: + bidDict[str(LastPrice)] = Volume + # indexFinal = indexTick + bidDictResult,askDictResult = process(bidDict,askDict,symbol) + bidDictResult=dict(sorted(bidDictResult.items(),key=operator.itemgetter(0))) + askDictResult=dict(sorted(askDictResult.items(),key=operator.itemgetter(0))) + prinslist=list(bidDictResult.keys()) + asklist=list(askDictResult.values()) + bidlist=list(bidDictResult.values()) + delta=(sum(askDictResult.values()) - sum(bidDictResult.values())) + #print(prinslist,asklist,bidlist) + #print(len(prinslist),len(bidDictResult),len(askDictResult)) + df=pd.DataFrame({'price':pd.Series([prinslist]),'Ask':pd.Series([asklist]),'Bid':pd.Series([bidlist])}) + #df=pd.DataFrame({'price':pd.Series(bidDictResult.keys()),'Ask':pd.Series(askDictResult.values()),'Bid':pd.Series(bidDictResult.values())}) + df['symbol']=bar_symbol + df['datetime']=dt + df['delta']=str(delta) + df['close']=bar_close + df['open']=bar_open + df['high']=bar_high + df['low']=bar_low + df['volume']=bar_vol + #df['ticktime']=tTickArray[0] + df['dj'] = GetOrderFlow_dj(df) + ofdatadict[symbol]=df + +#公众号:松鼠Quant +#主页:www.quant789.com +#本策略仅作学习交流使用,实盘交易盈亏投资者个人负责!!! +#版权归松鼠Quant所有,禁止转发、转卖源码违者必究。 + +def GetOrderFlow_dj(kData): + Config = { + 'Value1': 3, + 'Value2': 3, + 'Value3': 3, + 'Value4': True, + } + aryData = kData + djcout = 0 + + # 遍历kData中的每一行,计算djcout指标 + for index, row in aryData.iterrows(): + kItem = aryData.iloc[index] + high = kItem['high'] + low = kItem['low'] + close = kItem['close'] + open = kItem['open'] + dtime = kItem['datetime'] + price_s = kItem['price'] + Ask_s = kItem['Ask'] + Bid_s = kItem['Bid'] + delta = kItem['delta'] + + price_s = price_s + Ask_s = Ask_s + Bid_s = Bid_s + + gj = 0 + xq = 0 + gxx = 0 + xxx = 0 + + # 遍历price_s中的每一个元素,计算相关指标 + for i in np.arange(0, len(price_s), 1): + duiji = { + 'price': 0, + 'time': 0, + 'longshort': 0, + } + + if i == 0: + delta = delta + + order= { + "Price":price_s[i], + "Bid":{ "Value":Bid_s[i]}, + "Ask":{ "Value":Ask_s[i]} + } + #空头堆积 + if i >= 0 and i < len(price_s) - 1: + if (order["Bid"]["Value"] > Ask_s[i + 1] * int(Config['Value1'])): + gxx += 1 + gj += 1 + if gj >= int(Config['Value2']) and Config['Value4'] == True: + duiji['price'] = price_s[i] + duiji['time'] = dtime + duiji['longshort'] = -1 + if float(duiji['price']) > 0: + djcout += -1 + else: + gj = 0 + #多头堆积 + if i >= 1 and i <= len(price_s) - 1: + if (order["Ask"]["Value"] > Bid_s[i - 1] * int(Config['Value1'])): + xq += 1 + xxx += 1 + if xq >= int(Config['Value2']) and Config['Value4'] == True: + duiji['price'] = price_s[i] + duiji['time'] = dtime + duiji['longshort'] = 1 + if float(duiji['price']) > 0: + djcout += 1 + else: + xq = 0 + + # 返回计算得到的djcout值 + return djcout + +#交易程序--------------------------------------------------------------------------------------------------------------------------------------------------------------------- + +class MyTrader(TraderApiBase): + def __init__(self, broker_id, td_server, investor_id, password, app_id, auth_code, md_queue=None, page_dir='', private_resume_type=2, public_resume_type=2): + # Cython类不使用super().__init__()方式调用父类初始化方法 + # TraderApiBase.__init__会由Cython自动处理 + + self.py=30 #设置委托价格的偏移,更加容易促成成交。仅螺纹,其他品种根据最小点波动,自己设置 + self.cont_df=0 + self.trailing_stop_percent = 0 #跟踪出场参数 + self.fixed_stop_loss_percent = 0 #固定出场参数 + self.dj_X=1 #开仓的堆积参数 + + self.pos=0 + self.Lots=1 #下单手数 + self.short_trailing_stop_price = 0 + self.long_trailing_stop_price = 0 + self.sl_long_price=0 + self.sl_shor_price=0 + self.out_long=0 + self.out_short=0 + self.clearing_executed=False + self.day_closed = False # 添加日内平仓标志 + self.kgdata = True #历史数据加载一次 + self.holddata=True #持仓数据加载一次 + self.use_ai_model = True # 是否使用AI模型来分析 + self.data_saved_1 = False + self.data_saved_2 = False + self.symbols='au2506' + # 新增止盈止损字典,按合约ID索引 + self.stop_order_dict = {} + + # 新增历史数据加载相关参数 + self.load_history = False # 是否加载历史数据 + self.history_rows = 30 # 默认加载30行历史数据 + self.trader_rows = 10 # 当tader_df里的数据大于10行时开始计算指标及触发AI模型 + + # 创建并启动保存数据的线程 + self.save_data_thread = threading.Thread(target=self.run_save_last_bar_data) + self.save_data_thread.daemon = True # 设置为守护线程,主程序退出时自动结束 + self.save_data_thread.start() + + def run_save_last_bar_data(self): + """ + 在子线程中定期调用save_last_bar_data方法 + """ + while True: + try: + # 调用保存数据的方法 + self.save_last_bar_data() + # 每50秒检查一次 + time.sleep(50) + except Exception as e: + print(f"保存数据线程出现异常: {e}") + import traceback + traceback.print_exc() + # 异常后暂停一会再继续 + time.sleep(30) + + def load_history_data(self, instrument_id): + """ + 加载历史数据 + + Args: + instrument_id: 合约ID + """ + if not self.load_history: + return + + try: + # 不再只提取英文字母,使用完整的合约代码 + symbol = str(instrument_id) + json_file_path = f"traderdata/{symbol}_ofdata.json" + + # 检查traderdata目录是否存在 + if not os.path.exists("traderdata"): + print(f"traderdata目录不存在,创建目录") + os.makedirs("traderdata") + + if os.path.exists(json_file_path): + try: + # 读取JSON文件,使用lines=True确保正确读取每行JSON + df = pd.read_json(json_file_path, lines=True) + + if len(df) == 0: + print(f"历史数据文件为空: {json_file_path}") + print("将使用实时数据开始交易") + return False + + # 如果数据行数超过设定的历史行数,只取最后N行 + if len(df) > self.history_rows: + df = df.tail(self.history_rows) + print(f"历史数据超过设定行数,仅加载最后{self.history_rows}行") + + # 更新全局trader_df + global trader_df + trader_df = df + + print(f"\n===== 历史数据加载成功 =====") + print(f"合约: {instrument_id}") + print(f"数据行数: {len(df)}行") + print(f"数据时间范围: {df['datetime'].iloc[0]} 到 {df['datetime'].iloc[-1]}") + print(f"最新价格: {df['close'].iloc[-1]}") + print(f"最新成交量: {df['volume'].iloc[-1]}") + print("===========================\n") + + # 更新cont_df + self.cont_df = len(df) + + # 计算日均线 + if len(df) > 0: + df['dayma'] = df['close'].mean() + + # 计算累积的delta值 + df['delta'] = df['delta'].astype(float) + df['delta累计'] = df['delta'].cumsum() + + return True + except Exception as e: + print(f"\n===== 历史数据加载错误 =====") + print(f"合约: {instrument_id}") + print(f"读取JSON错误: {e}") + print("将使用实时数据开始交易") + print("===========================\n") + return False + else: + print(f"\n===== 历史数据加载提示 =====") + print(f"合约: {instrument_id}") + print(f"未找到历史数据文件: {json_file_path}") + print("将使用实时数据开始交易") + print("===========================\n") + return False + + except Exception as e: + print(f"\n===== 历史数据加载错误 =====") + print(f"合约: {instrument_id}") + print(f"错误信息: {e}") + print("将使用实时数据开始交易") + print("===========================\n") + return False + + #读取保存的数据 + def read_to_csv(self,symbol): + # 文件夹路径和文件路径 + # 使用完整的合约代码 + symbol = str(symbol) + folder_path = "traderdata" + file_path = os.path.join(folder_path, f"{symbol}traderdata.csv") + # 如果文件夹不存在则创建 + if not os.path.exists(folder_path): + os.makedirs(folder_path, exist_ok=True) + + # 读取保留的模型数据CSV文件 + if os.path.exists(file_path): + try: + # 检查文件是否为空 + if os.path.getsize(file_path) == 0: + print(f"CSV文件为空: {file_path}") + return + + df = pd.read_csv(file_path) + if not df.empty and self.holddata==True: + # 选择最后一行数据 + row = df.iloc[-1] + # 根据CSV文件的列名将数据赋值给相应的属性 + self.pos = int(row['pos']) + self.short_trailing_stop_price = float(row['short_trailing_stop_price']) + self.long_trailing_stop_price = float(row['long_trailing_stop_price']) + self.sl_long_price = float(row['sl_long_price']) + self.sl_shor_price = float(row['sl_shor_price']) + # self.out_long = int(row['out_long']) + # self.out_short = int(row['out_short']) + print("找到历史交易数据文件,已经更新持仓,止损止盈数据", df.iloc[-1]) + self.holddata=False + except pd.errors.EmptyDataError: + print(f"CSV文件格式错误或为空: {file_path}") + except Exception as e: + print(f"读取CSV文件时出错: {e}") + else: + pass + #print("没有找到历史交易数据文件", file_path) + #如果没有找到CSV,则初始化变量 + + pass + + #保存数据 + def save_to_csv(self,symbol): + # 使用完整的合约代码 + symbol = str(symbol) + # 创建DataFrame + data = { + 'datetime': [datetime.now().strftime('%Y-%m-%d %H:%M:%S')], # 使用当前时间 + 'pos': [self.pos], + 'short_trailing_stop_price': [self.short_trailing_stop_price], + 'long_trailing_stop_price': [self.long_trailing_stop_price], + 'sl_long_price': [self.sl_long_price], + 'sl_shor_price': [self.sl_shor_price], + } + + df = pd.DataFrame(data) + + # 确保目录存在 + folder_path = "traderdata" + if not os.path.exists(folder_path): + os.makedirs(folder_path, exist_ok=True) + + file_path = os.path.join(folder_path, f"{symbol}traderdata.csv") + + try: + # 将DataFrame保存到CSV文件 + df.to_csv(file_path, index=False) + print(f"持仓数据已保存到: {file_path}") + except Exception as e: + print(f"保存CSV文件时出错: {e}") + + + def save_last_bar_data(self): + # 获取当前时间 + current_time = datetime.now().time() + + # 第一时间范围 + clearing_time1_start = s_time(14,55) + clearing_time1_end = s_time(15,00) + # 计算clearing_time1_end加5分钟 + clearing_time1_end_plus5 = (datetime.combine(datetime.today(), clearing_time1_end) + timedelta(minutes=5)).time() + + # 第二时间范围 + clearing_time2_start = s_time(2,25) + clearing_time2_end = s_time(2,30) + # 计算clearing_time2_end加5分钟 + clearing_time2_end_plus5 = (datetime.combine(datetime.today(), clearing_time2_end) + timedelta(minutes=5)).time() + + instrument_id = self.symbols + json_file_path = f"traderdata/{instrument_id}_ofdata.json" + + # 检查是否已经有对应收盘时间的数据 + has_closing_data = False + if os.path.exists(json_file_path): + try: + # 读取现有JSON文件 + existing_df = pd.read_json(json_file_path, lines=True) + if not existing_df.empty: + # 获取最后一行数据的datetime + last_datetime = existing_df.iloc[-1]['datetime'] + + # 如果是Timestamp类型,直接获取time() + if isinstance(last_datetime, pd.Timestamp): + last_time = last_datetime.time() + # 如果是字符串类型,先转换为datetime + else: + last_datetime = pd.to_datetime(str(last_datetime)) + last_time = last_datetime.time() + + # 检查是否已经有了收盘时间的数据 + if (last_time == clearing_time1_end): + print(f"已有15:00收盘数据: {last_datetime}, 无需追加") + self.data_saved_1 = True + has_closing_data = True + elif (last_time == clearing_time2_end): + print(f"已有2:30收盘数据: {last_datetime}, 无需追加") + self.data_saved_2 = True + has_closing_data = True + except Exception as e: + print(f"读取JSON文件检查收盘数据时出错: {e}") + import traceback + traceback.print_exc() + + # 保存最后一个bar的数据到JSON文件(当时间在第一个时间段结束后的5分钟内) + if current_time >= clearing_time1_end and current_time < clearing_time1_end_plus5 and not self.data_saved_1 and not has_closing_data: + if len(trader_df) > 0: + print("第一时间段结束,保存最后一个完整bar数据到行情JSON") + + # 确保目录存在 + if not os.path.exists("traderdata"): + os.makedirs("traderdata", exist_ok=True) + + # 确保待保存的新数据中datetime字段是格式化的日期时间字符串 + if 'datetime' in trader_df.columns: + trader_df['datetime'] = trader_df['datetime'].astype(str) + + # 只获取最后一个bar的数据 + last_bar = trader_df.tail(1) + + if os.path.exists(json_file_path): + try: + # 读取现有数据 + existing_df = pd.read_json(json_file_path, lines=True) + + # 确保现有数据中的datetime字段是字符串类型 + if 'datetime' in existing_df.columns: + existing_df['datetime'] = existing_df['datetime'].astype(str) + + # 合并新数据 + combined_df = pd.concat([existing_df, last_bar], ignore_index=True) + # 保存合并后的数据,使用lines=True确保每行是独立的JSON对象 + combined_df.to_json(json_file_path, orient='records', force_ascii=False, lines=True) + print(f"最后一个bar数据已保存到行情JSON: {json_file_path}") + except Exception as e: + print(f"读取或保存JSON文件时出错: {e}") + # 如果读取出错,直接保存当前数据 + last_bar.to_json(json_file_path, orient='records', force_ascii=False, lines=True) + else: + # 创建新文件并保存最后一个bar数据 + last_bar.to_json(json_file_path, orient='records', force_ascii=False, lines=True) + print(f"创建新的行情JSON并保存最后一个bar: {json_file_path}") + + self.data_saved_1 = True # 设置标志,防止重复保存 + + # 保存最后一个bar的数据到JSON文件(当时间在第二个时间段结束后的5分钟内) + if current_time >= clearing_time2_end and current_time < clearing_time2_end_plus5 and not self.data_saved_2 and not has_closing_data: + if len(trader_df) > 0: + print("第二时间段结束,保存最后一个完整bar数据到行情JSON") + + # 确保目录存在 + if not os.path.exists("traderdata"): + os.makedirs("traderdata", exist_ok=True) + + # 确保待保存的新数据中datetime字段是格式化的日期时间字符串 + if 'datetime' in trader_df.columns: + trader_df['datetime'] = trader_df['datetime'].astype(str) + + # 只获取最后一个bar的数据 + last_bar = trader_df.tail(1) + + if os.path.exists(json_file_path): + try: + # 读取现有数据 + existing_df = pd.read_json(json_file_path, lines=True) + + # 确保现有数据中的datetime字段是字符串类型 + if 'datetime' in existing_df.columns: + existing_df['datetime'] = existing_df['datetime'].astype(str) + + # 合并新数据 + combined_df = pd.concat([existing_df, last_bar], ignore_index=True) + # 保存合并后的数据,使用lines=True确保每行是独立的JSON对象 + combined_df.to_json(json_file_path, orient='records', force_ascii=False, lines=True) + print(f"最后一个bar数据已保存到行情JSON: {json_file_path}") + except Exception as e: + print(f"读取或保存JSON文件时出错: {e}") + # 如果读取出错,直接保存当前数据 + last_bar.to_json(json_file_path, orient='records', force_ascii=False, lines=True) + else: + # 创建新文件并保存最后一个bar数据 + last_bar.to_json(json_file_path, orient='records', force_ascii=False, lines=True) + print(f"创建新的行情JSON并保存最后一个bar: {json_file_path}") + + self.data_saved_2 = True # 设置标志,防止重复保存 + + + + #每日收盘重置数据 + def day_data_reset(self,data): + # 获取当前时间 + current_time = datetime.now().time() + + # 第一时间范围 + clearing_time1_start = s_time(14,55) + clearing_time1_end = s_time(15,00) + # 第二时间范围 + clearing_time2_start = s_time(2,25) + clearing_time2_end = s_time(2,30) + current_bid = float(data['BidPrice1']) # 当前买价 + current_ask = float(data['AskPrice1']) # 当前卖价 + + + self.clearing_executed = False + # 检查当前时间第一个操作的时间范围内 + if clearing_time1_start <= current_time < clearing_time1_end and not self.clearing_executed: + self.clearing_executed = True # 设置标志变量为已执行 + + # 如果有持仓,强制平仓 + if self.pos != 0: + print("交易日结束,开始强制平仓") + # 遍历所有合约发送平仓指令 + for instrument_id in list(self.stop_order_dict.keys()): + stops = self.stop_order_dict[instrument_id] + + # 平多仓 + if stops['long']['position'] > 0: + print(f"发送平多仓指令: {instrument_id}, 手数: {stops['long']['position']}, 价格: {current_bid}") + self.insert_order(data['ExchangeID'], data['InstrumentID'], + current_bid - self.py, + stops['long']['position'], + b'1', b'3') + # 平空仓 + if stops['short']['position'] > 0: + print(f"发送平空仓指令: {instrument_id}, 手数: {stops['short']['position']}, 价格: {current_ask}") + self.insert_order(data['ExchangeID'], data['InstrumentID'], + current_ask + self.py, + stops['short']['position'], + b'0', b'3') + + # 清空所有合约的持仓信息 + for instrument_id in list(self.stop_order_dict.keys()): + self.clear_position_info(instrument_id, 'all') + self.day_closed = True # 设置日内平仓标志 + print("日内交易已结束,禁止开新仓") + + # 检查当前时间是否在第二个操作的时间范围内 + elif clearing_time2_start <= current_time < clearing_time2_end and not self.clearing_executed: + self.clearing_executed = True # 设置标志变量为已执行 + + # 如果有持仓,强制平仓 + if self.pos != 0: + print("交易日结束,开始强制平仓") + # 遍历所有合约发送平仓指令 + for instrument_id in list(self.stop_order_dict.keys()): + stops = self.stop_order_dict[instrument_id] + + # 平多仓 + if stops['long']['position'] > 0: + print(f"发送平多仓指令: {instrument_id}, 手数: {stops['long']['position']}, 价格: {current_bid}") + self.insert_order(data['ExchangeID'], data['InstrumentID'], + current_bid - self.py, + stops['long']['position'], + b'1', b'3') + # 平空仓 + if stops['short']['position'] > 0: + print(f"发送平空仓指令: {instrument_id}, 手数: {stops['short']['position']}, 价格: {current_ask}") + self.insert_order(data['ExchangeID'], data['InstrumentID'], + current_ask + self.py, + stops['short']['position'], + b'0', b'3') + + # 清空所有合约的持仓信息 + for instrument_id in list(self.stop_order_dict.keys()): + self.clear_position_info(instrument_id, 'all') + self.day_closed = True # 设置日内平仓标志 + print("日内交易已结束,禁止开新仓") + else: + self.clearing_executed = False + self.day_closed = False + return self.clearing_executed + + def OnRtnTrade(self, pTrade): + print("||成交回报||", pTrade) + + # 获取成交信息 + instrument_id = pTrade['InstrumentID'].decode() + direction = pTrade['Direction'].decode() # '0'为买入,'1'为卖出 + offset_flag = pTrade['OffsetFlag'].decode() # '0'为开仓,'1'为平仓,'3'为平今 + volume = pTrade['Volume'] + price = pTrade['Price'] + + # 根据成交类型更新持仓信息 + if offset_flag in ['1', '3']: # 平仓或平今 + # 判断平的是多头还是空头 + if direction == '1': # 卖出,平多头 + print(f"平多头成交: {instrument_id}, 价格: {price}, 数量: {volume}") + # 清空多头持仓信息 + self.clear_position_info(instrument_id, 'long') + else: # 买入,平空头 + print(f"平空头成交: {instrument_id}, 价格: {price}, 数量: {volume}") + # 清空空头持仓信息 + self.clear_position_info(instrument_id, 'short') + + elif offset_flag == '0': # 开仓 + if direction == '0': # 买入,开多头 + print(f"开多头成交: {instrument_id}, 价格: {price}, 数量: {volume}") + # 如果有空头持仓,先清空 + if instrument_id in self.stop_order_dict and self.stop_order_dict[instrument_id]['short']['position'] > 0: + self.clear_position_info(instrument_id, 'short') + + # # 设置多头持仓信息 + # sl_price = price * (1 - self.fixed_stop_loss_percent) # 默认止损价 + # tp_price = price * (1 + self.trailing_stop_percent) # 默认止盈价 + + # # 设置初始跟踪止损价,与开仓价保持一定距离 + # initial_trailing_stop = price * (1 - self.trailing_stop_percent) + + # log_message = f"设置止损价: {sl_price}, 止盈价: {tp_price}, 跟踪止损价: {initial_trailing_stop}, 跟踪百分比: {self.trailing_stop_percent*100:.3f}%" + # STOPLOSS_LOGGER.info(log_message) + + # # 更新多头持仓信息,设置合理的跟踪止损初始值 + # self.update_stop_order_dict(instrument_id, 'long', volume, price, sl_price, tp_price, initial_trailing_stop) + # self.pos = volume # 更新全局持仓状态 + + # # 兼容旧代码 + # self.long_trailing_stop_price = initial_trailing_stop + # self.sl_long_price = sl_price + # self.save_to_csv(instrument_id) + + else: # 卖出,开空头 + print(f"开空头成交: {instrument_id}, 价格: {price}, 数量: {volume}") + # 如果有多头持仓,先清空 + if instrument_id in self.stop_order_dict and self.stop_order_dict[instrument_id]['long']['position'] > 0: + self.clear_position_info(instrument_id, 'long') + + # # 设置空头持仓信息 + # sl_price = price * (1 + self.fixed_stop_loss_percent) # 默认止损价 + # tp_price = price * (1 - self.trailing_stop_percent) # 默认止盈价 + + # # 设置初始跟踪止损价,与开仓价保持一定距离 + # initial_trailing_stop = price * (1 + self.trailing_stop_percent) + + # log_message = f"设置止损价: {sl_price}, 止盈价: {tp_price}, 跟踪止损价: {initial_trailing_stop}, 跟踪百分比: {self.trailing_stop_percent*100:.3f}%" + # STOPLOSS_LOGGER.info(log_message) + + # # 更新空头持仓信息,设置合理的跟踪止损初始值 + # self.update_stop_order_dict(instrument_id, 'short', self.Lots, price, sl_price, tp_price, initial_trailing_stop) + # self.pos = -1 # 更新全局持仓状态 + + # # 兼容旧代码 + # self.short_trailing_stop_price = initial_trailing_stop + # self.sl_shor_price = sl_price + # self.save_to_csv(instrument_id) + + def OnRspOrderInsert(self, pInputOrder, pRspInfo, nRequestID, bIsLast): + print("||OnRspOrderInsert||", pInputOrder, pRspInfo, nRequestID, bIsLast) + + #公众号:松鼠Quant + #主页:www.quant789.com + #本策略仅作学习交流使用,实盘交易盈亏投资者个人负责!!! + #版权归松鼠Quant所有,禁止转发、转卖源码违者必究。 + + #注意:运行前请先安装好algoplus, + # pip install AlgoPlus + #http://www.algo.plus/ctp/python/0103001.html + + # 订单状态通知 + def OnRtnOrder(self, pOrder): + print("||订单回报||", pOrder) + + def Join(self): + data = None + # 记录上次加载止盈止损信息的时间和合约 + last_load_time = {} + + while True: + if self.status == 0 and not self.md_queue.empty(): + + while not self.md_queue.empty(): + data = self.md_queue.get(block=False) + instrument_id = data['InstrumentID'].decode() # 品种代码 + self.symbols=instrument_id + # 首次运行时加载历史数据 + if self.kgdata: + self.load_history_data(instrument_id) + self.kgdata = False + + # 加载该合约的止盈止损信息,避免频繁加载 + current_time = time.time() + if instrument_id not in last_load_time or current_time - last_load_time.get(instrument_id, 0) > 60: # 每60秒才重新加载一次 + self.load_stop_orders_from_file(instrument_id) + last_load_time[instrument_id] = current_time + + # 检查止盈止损条件 + self.check_stop_conditions(data) + + # 在每个tick都检查和处理AI交易信号 - 移到这里以提高执行速度 + if self.use_ai_model: + self.check_and_process_ai_signals(data) + + # 原有代码... + self.read_to_csv(instrument_id) + self.day_data_reset(data) + tickcome(data) + #新K线开始,启动交易程序 and 保存行情数据 + if len(trader_df)>self.cont_df and len(trader_df)>0: + # 计算日均线 + trader_df['dayma'] = trader_df['close'].mean() + + # 计算累积的delta值 + trader_df['delta'] = trader_df['delta'].astype(float) + trader_df['delta累计'] = trader_df['delta'].cumsum() + + # 检查文件是否存在 + json_file_path = f"traderdata/{instrument_id}_ofdata.json" + + # 确保待保存的新数据中datetime字段是格式化的日期时间字符串 + if 'datetime' in trader_df.columns: + # 无论什么类型,都统一转换为字符串格式 + trader_df['datetime'] = trader_df['datetime'].astype(str) + + if os.path.exists(json_file_path): + try: + # 读取现有数据 + existing_df = pd.read_json(json_file_path, lines=True) + + # 确保现有数据中的datetime字段是字符串类型 + if 'datetime' in existing_df.columns: + existing_df['datetime'] = existing_df['datetime'].astype(str) + + # 合并新数据 + combined_df = pd.concat([existing_df, trader_df.tail(1)], ignore_index=True) + # 保存合并后的数据,使用lines=True确保每行是独立的JSON对象 + combined_df.to_json(json_file_path, orient='records', force_ascii=False, lines=True) + except Exception as e: + print(f"读取或保存JSON文件时出错: {e}") + # 如果读取出错,直接保存当前数据 + trader_df.to_json(json_file_path, orient='records', force_ascii=False, lines=True) + else: + # 创建新文件并保存整个DataFrame + trader_df.to_json(json_file_path, orient='records', force_ascii=False, lines=True) + + # 更新跟踪止损价格 - 兼容旧版本代码 + if self.long_trailing_stop_price >0 and self.pos>0: + self.long_trailing_stop_price = trader_df['low'].iloc[-1] if self.long_trailing_stop_price0 and self.pos<0: + self.short_trailing_stop_price = trader_df['high'].iloc[-1] if trader_df['high'].iloc[-1] self.trader_rows: + AI_THREAD_RUNNING = True + ai_thread = threading.Thread( + target=self.background_model_call, + args=(trader_df, instrument_id) + ) + ai_thread.daemon = True # 设置为守护线程,主程序退出时自动结束 + ai_thread.start() + print("启动AI分析线程...") + + print(trader_df['datetime']) + self.cont_df=len(trader_df) + else: + time.sleep(0.5) + + def background_model_call(self, data_df, instrument_id): + """ + 在后台线程中调用大模型,并将交易信号放入队列 + + Args: + data_df: 包含订单流数据的DataFrame + instrument_id: 合约ID + """ + global AI_THREAD_RUNNING + + start_time = datetime.now() + log_message = f"\n===== 开始AI分析 [{start_time.strftime('%Y-%m-%d %H:%M:%S')}] =====" + print(log_message) + AI_LOGGER.info(log_message) + + log_message = f"正在分析合约: {instrument_id}" + print(log_message) + AI_LOGGER.info(log_message) + + try: + # 复制DataFrame以避免在不同线程间共享数据可能导致的问题 + df_copy = data_df.copy() + + # 输出分析的数据行数 + log_message = f"分析数据行数: {len(df_copy)}" + print(log_message) + AI_LOGGER.info(log_message) + + log_message = f"最新价格: {df_copy['close'].iloc[-1] if len(df_copy) > 0 else 'N/A'}" + print(log_message) + AI_LOGGER.info(log_message) + + # 调用大模型获取交易信号 + trading_signal = call_deepseek_model(df_copy, self) # 传递self参数 + + # 计算分析耗时 + end_time = datetime.now() + elapsed = (end_time - start_time).total_seconds() + + # 将交易信号和合约ID一起放入队列 + signal_data = { + 'signal': trading_signal, + 'instrument_id': instrument_id, + 'timestamp': end_time # 使用结束时间作为时间戳 + } + + AI_SIGNAL_QUEUE.put(signal_data) + + log_message = f"AI模型分析完成,结果已放入队列,耗时: {elapsed:.2f}秒" + print(log_message) + AI_LOGGER.info(log_message) + + log_message = f"分析结果: {trading_signal}" + print(log_message) + AI_LOGGER.info(log_message) + + log_message = "===== AI分析完成 =====" + print(log_message + "\n") + AI_LOGGER.info(log_message) + except Exception as e: + end_time = datetime.now() + elapsed = (end_time - start_time).total_seconds() + + log_message = f"AI模型分析线程出现异常: {e}" + print(log_message) + AI_LOGGER.error(log_message) + + print(f"异常详情:") + import traceback + error_traceback = traceback.format_exc() + AI_LOGGER.error(f"异常详情:\n{error_traceback}") + traceback.print_exc() + + log_message = f"分析失败,耗时: {elapsed:.2f}秒" + print(log_message) + AI_LOGGER.error(log_message) + + log_message = "===== AI分析异常结束 =====" + print(log_message + "\n") + AI_LOGGER.error(log_message) + finally: + # 标记线程已完成 + AI_THREAD_RUNNING = False + + + #公众号:松鼠Quant + #主页:www.quant789.com + #本策略仅作学习交流使用,实盘交易盈亏投资者个人负责!!! + #版权归松鼠Quant所有,禁止转发、转卖源码违者必究。 + + #注意:运行前请先安装好algoplus, + # pip install AlgoPlus + #http://www.algo.plus/ctp/python/0103001.html + + def check_and_process_ai_signals(self, data): + """检查并处理AI产生的交易信号""" + if AI_SIGNAL_QUEUE.empty(): + return + + # 从队列中获取信号 + signal_data = AI_SIGNAL_QUEUE.get() + trading_signal = signal_data['signal'] + instrument_id = signal_data['instrument_id'] + signal_time = signal_data['timestamp'] + + # 验证合约ID是否匹配,不匹配则放回队列 + if instrument_id != data['InstrumentID'].decode(): + AI_SIGNAL_QUEUE.put(signal_data) + return + + # 提取交易信号数据 + action = trading_signal.get('action', '不操作') + confidence = trading_signal.get('confidence', 0) + reason = trading_signal.get('reason', '') + stop_loss = trading_signal.get('stop_loss', 0) + take_profit = trading_signal.get('take_profit', 0) + trailing_percent = trading_signal.get('trailing_percent', 0) + + # 记录日志 + log_lines = [ + f"\n===== 执行AI模型交易信号 [{datetime.now().strftime('%Y-%m-%d %H:%M:%S')}] =====", + f"信号生成时间: {signal_time.strftime('%Y-%m-%d %H:%M:%S')}", + f"信号类型: {action}", + f"置信度: {confidence}", + f"理由: {reason}" + ] + for line in log_lines: + print(line) + SIGNAL_LOGGER.info(line) + + # 确保合约在止损止盈字典中 + self._ensure_stop_order_dict(instrument_id) + current_stops = self.stop_order_dict[instrument_id] + + # 处理跟踪止损百分比更新 + self._update_trailing_stop_percent(trailing_percent, instrument_id, data) + + # 只有当置信度大于等于6时才执行交易 + if confidence < 6: + print(f"信号置信度{confidence}低于执行阈值(6),不执行交易") + print("===== 交易信号处理完成 =====\n") + return + + print(f"开始执行交易,当前价格: 买一{data['BidPrice1']} / 卖一{data['AskPrice1']}") + + # 根据不同交易行为执行相应操作 + if action == '开多' and current_stops['long']['position'] <= 0: + self._handle_open_long(data, instrument_id, stop_loss, take_profit) + + elif action == '开空' and current_stops['short']['position'] <= 0: + self._handle_open_short(data, instrument_id, stop_loss, take_profit) + + elif action == '平多' and current_stops['long']['position'] > 0: + self._handle_close_long(data, instrument_id) + + elif action == '平空' and current_stops['short']['position'] > 0: + self._handle_close_short(data, instrument_id) + + elif action == '平多开空' and current_stops['long']['position'] > 0: + self._handle_close_long_open_short(data, instrument_id, stop_loss, take_profit) + + elif action == '平空开多' and current_stops['short']['position'] > 0: + self._handle_close_short_open_long(data, instrument_id, stop_loss, take_profit) + + elif action == '不操作': + self._handle_adjust_stop_levels(instrument_id, stop_loss, take_profit) + + print("===== 交易信号执行完成 =====\n") + + def _ensure_stop_order_dict(self, instrument_id): + """确保指定合约在止损止盈字典中存在""" + if instrument_id not in self.stop_order_dict: + self.stop_order_dict[instrument_id] = { + 'long': {'position': 0, 'entry_price': 0, 'stop_loss': 0, 'take_profit': 0, 'trailing_stop': 0}, + 'short': {'position': 0, 'entry_price': 0, 'stop_loss': 0, 'take_profit': 0, 'trailing_stop': 0} + } + + def _update_trailing_stop_percent(self, trailing_percent, instrument_id, data): + """更新跟踪止损百分比""" + if not (0.0001 <= trailing_percent <= 0.001): + return + + old_percent = self.trailing_stop_percent + self.trailing_stop_percent = trailing_percent + log_message = f"更新跟踪止损百分比参数: {old_percent*100:.3f}% -> {trailing_percent*100:.3f}%" + STOPLOSS_LOGGER.info(log_message) + + current_stops = self.stop_order_dict[instrument_id] + + # 更新多头持仓的跟踪止损价 + if current_stops['long']['position'] > 0: + new_trailing_stop = float(data['BidPrice1']) * (1 - self.trailing_stop_percent) + old_trailing_stop = current_stops['long']['trailing_stop'] + + if new_trailing_stop > old_trailing_stop: + self.update_stop_order_dict(instrument_id, 'long', None, None, None, None, new_trailing_stop) + self.long_trailing_stop_price = new_trailing_stop # 兼容旧代码 + self.save_to_csv(instrument_id) + + # 更新空头持仓的跟踪止损价 + elif current_stops['short']['position'] > 0: + new_trailing_stop = float(data['AskPrice1']) * (1 + self.trailing_stop_percent) + old_trailing_stop = current_stops['short']['trailing_stop'] + + if new_trailing_stop < old_trailing_stop or old_trailing_stop == 0: + self.update_stop_order_dict(instrument_id, 'short', None, None, None, None, new_trailing_stop) + self.short_trailing_stop_price = new_trailing_stop # 兼容旧代码 + self.save_to_csv(instrument_id) + + def _handle_open_long(self, data, instrument_id, stop_loss, take_profit): + """处理开多头仓位""" + # 如果持有空头头寸,先平空 + current_stops = self.stop_order_dict[instrument_id] + if current_stops['short']['position'] > 0: + print('执行平空操作') + self.insert_order(data['ExchangeID'], data['InstrumentID'], + data['AskPrice1']+self.py, + current_stops['short']['position'], + b'0', b'3') + self.clear_position_info(instrument_id, 'short') + + # 开多 + print('执行开多操作') + entry_price = float(data['AskPrice1']) + self.insert_order(data['ExchangeID'], data['InstrumentID'], + entry_price+self.py, self.Lots, b'0', b'0') + + # 设置止损止盈 + sl_price = stop_loss + tp_price = take_profit + initial_trailing_stop = entry_price * (1 - self.trailing_stop_percent) + + # 记录止损止盈设置 + STOPLOSS_LOGGER.info(f"设置止损价: {sl_price}, 止盈价: {tp_price}, 跟踪止损价: {initial_trailing_stop}, 跟踪百分比: {self.trailing_stop_percent*100:.3f}%") + + # 更新持仓信息 + self.update_stop_order_dict(instrument_id, 'long', self.Lots, entry_price, sl_price, tp_price, initial_trailing_stop) + self.pos = 1 # 更新全局持仓状态 + + # 兼容旧代码 + self.long_trailing_stop_price = initial_trailing_stop + self.sl_long_price = sl_price + self.save_to_csv(instrument_id) + + def _handle_open_short(self, data, instrument_id, stop_loss, take_profit): + """处理开空头仓位""" + # 如果持有多头头寸,先平多 + current_stops = self.stop_order_dict[instrument_id] + if current_stops['long']['position'] > 0: + print('执行平多操作') + self.insert_order(data['ExchangeID'], data['InstrumentID'], + data['BidPrice1']-self.py, + current_stops['long']['position'], + b'1', b'3') + self.clear_position_info(instrument_id, 'long') + + # 开空 + print('执行开空操作') + entry_price = float(data['BidPrice1']) + self.insert_order(data['ExchangeID'], data['InstrumentID'], + entry_price-self.py, self.Lots, b'1', b'0') + + # 设置止损止盈 + sl_price = stop_loss + tp_price = take_profit + initial_trailing_stop = entry_price * (1 + self.trailing_stop_percent) + + # 记录止损止盈设置 + STOPLOSS_LOGGER.info(f"设置止损价: {sl_price}, 止盈价: {tp_price}, 跟踪止损价: {initial_trailing_stop}, 跟踪百分比: {self.trailing_stop_percent*100:.3f}%") + + # 更新持仓信息 + self.update_stop_order_dict(instrument_id, 'short', self.Lots, entry_price, sl_price, tp_price, initial_trailing_stop) + self.pos = -1 # 更新全局持仓状态 + + # 兼容旧代码 + self.short_trailing_stop_price = initial_trailing_stop + self.sl_shor_price = sl_price + self.save_to_csv(instrument_id) + + def _handle_close_long(self, data, instrument_id): + """处理平多头仓位""" + current_stops = self.stop_order_dict[instrument_id] + print('执行平多操作') + self.insert_order(data['ExchangeID'], data['InstrumentID'], + data['BidPrice1']-self.py, + current_stops['long']['position'], + b'1', b'3') + self.clear_position_info(instrument_id, 'long') + + def _handle_close_short(self, data, instrument_id): + """处理平空头仓位""" + current_stops = self.stop_order_dict[instrument_id] + print('执行平空操作') + self.insert_order(data['ExchangeID'], data['InstrumentID'], + data['AskPrice1']+self.py, + current_stops['short']['position'], + b'0', b'3') + self.clear_position_info(instrument_id, 'short') + + def _handle_close_long_open_short(self, data, instrument_id, stop_loss, take_profit): + """处理平多开空操作""" + print('执行平多开空操作') + + # 第一步:平多 + self._handle_close_long(data, instrument_id) + + # 第二步:开空 + print('2. 执行开空操作') + entry_price = float(data['BidPrice1']) + self.insert_order(data['ExchangeID'], data['InstrumentID'], + entry_price-self.py, self.Lots, b'1', b'0') + + # 设置止损止盈 + sl_price = stop_loss + tp_price = take_profit + initial_trailing_stop = entry_price * (1 + self.trailing_stop_percent) + + # 记录止损止盈设置 + STOPLOSS_LOGGER.info(f"设置止损价: {sl_price}, 止盈价: {tp_price}, 跟踪止损价: {initial_trailing_stop}, 跟踪百分比: {self.trailing_stop_percent*100:.3f}%") + + # 更新持仓信息 + self.update_stop_order_dict(instrument_id, 'short', self.Lots, entry_price, sl_price, tp_price, initial_trailing_stop) + self.pos = -1 # 更新全局持仓状态 + + # 兼容旧代码 + self.short_trailing_stop_price = initial_trailing_stop + self.sl_shor_price = sl_price + self.save_to_csv(instrument_id) + + def _handle_close_short_open_long(self, data, instrument_id, stop_loss, take_profit): + """处理平空开多操作""" + print('执行平空开多操作') + + # 第一步:平空 + self._handle_close_short(data, instrument_id) + + # 第二步:开多 + print('2. 执行开多操作') + entry_price = float(data['AskPrice1']) + self.insert_order(data['ExchangeID'], data['InstrumentID'], + entry_price+self.py, self.Lots, b'0', b'0') + + # 设置止损止盈 + sl_price = stop_loss + tp_price = take_profit + initial_trailing_stop = entry_price * (1 - self.trailing_stop_percent) + + # 记录止损止盈设置 + STOPLOSS_LOGGER.info(f"设置止损价: {sl_price}, 止盈价: {tp_price}, 跟踪止损价: {initial_trailing_stop}, 跟踪百分比: {self.trailing_stop_percent*100:.3f}%") + + # 更新持仓信息 + self.update_stop_order_dict(instrument_id, 'long', self.Lots, entry_price, sl_price, tp_price, initial_trailing_stop) + self.pos = 1 # 更新全局持仓状态 + + # 兼容旧代码 + self.long_trailing_stop_price = initial_trailing_stop + self.sl_long_price = sl_price + self.save_to_csv(instrument_id) + + def _handle_adjust_stop_levels(self, instrument_id, stop_loss, take_profit): + """调整止损止盈价格""" + current_stops = self.stop_order_dict[instrument_id] + + # 调整止损价 + if stop_loss > 0: + if current_stops['long']['position'] > 0: # 多头持仓 + self.update_stop_order_dict(instrument_id, 'long', None, None, stop_loss, None, None) + print(f'已调整多头止损价: {stop_loss}') + self.sl_long_price = stop_loss # 兼容旧代码 + self.save_to_csv(instrument_id) + elif current_stops['short']['position'] > 0: # 空头持仓 + self.update_stop_order_dict(instrument_id, 'short', None, None, stop_loss, None, None) + print(f'已调整空头止损价: {stop_loss}') + self.sl_shor_price = stop_loss # 兼容旧代码 + self.save_to_csv(instrument_id) + + # 调整止盈价 + if take_profit > 0: + if current_stops['long']['position'] > 0: # 多头持仓 + self.update_stop_order_dict(instrument_id, 'long', None, None, None, take_profit, None) + print(f'已调整多头止盈价: {take_profit}') + self.save_to_csv(instrument_id) + elif current_stops['short']['position'] > 0: # 空头持仓 + self.update_stop_order_dict(instrument_id, 'short', None, None, None, take_profit, None) + print(f'已调整空头止盈价: {take_profit}') + self.save_to_csv(instrument_id) + + #公众号:松鼠Quant + #主页:www.quant789.com + #本策略仅作学习交流使用,实盘交易盈亏投资者个人负责!!! + #版权归松鼠Quant所有,禁止转发、转卖源码违者必究。 + + #注意:运行前请先安装好algoplus, + # pip install AlgoPlus + #http://www.algo.plus/ctp/python/0103001.html + + def format_data_for_llm(self, df): + """ + 将DataFrame格式化为适合LLM分析的文本格式,包含历史交易信息 + """ + # 提取最近几条记录 + recent_data = df.tail(self.trader_rows) + + # 构建基本信息 + data_text = "订单流数据分析:\n\n" + + # 提取最新行情数据 + instrument_id = recent_data['symbol'].iloc[-1] + + # 添加最新价格和交易量信息 + data_text += f"当前时间: {recent_data['datetime'].iloc[-1]}\n" + data_text += f"当前价格: {recent_data['close'].iloc[-1]}\n" + data_text += f"开盘价: {recent_data['open'].iloc[-1]}\n" + data_text += f"最高价: {recent_data['high'].iloc[-1]}\n" + data_text += f"最低价: {recent_data['low'].iloc[-1]}\n" + data_text += f"成交量: {recent_data['volume'].iloc[-1]}\n" + + # 计算价格趋势 + if len(recent_data) >= 5: + price_trend = recent_data['close'].pct_change().tail(5).mean() * 100 + data_text += f"价格短期趋势: {'上涨' if price_trend > 0 else '下跌'} ({price_trend:.2f}%)\n" + + # 计算价格波动性 + if len(recent_data) >= 5: + volatility = recent_data['close'].pct_change().tail(5).std() * 100 + data_text += f"价格波动性: {volatility:.2f}%\n" + + # 添加支撑和阻力位分析 + recent_high = recent_data['high'].max() + recent_low = recent_data['low'].min() + data_text += f"近期阻力位: {recent_high}\n" + data_text += f"近期支撑位: {recent_low}\n" + + # 添加均线分析 - 计算5、10、20均线 + if len(df) >= 20: + # 计算均线 + ma5 = df['close'].rolling(5).mean().iloc[-1] + ma10 = df['close'].rolling(10).mean().iloc[-1] + ma20 = df['close'].rolling(20).mean().iloc[-1] + + data_text += f"MA5: {ma5:.2f}\n" + data_text += f"MA10: {ma10:.2f}\n" + data_text += f"MA20: {ma20:.2f}\n" + + # 判断均线形态 + if abs(ma5 - ma10) / ma10 < 0.01 and abs(ma10 - ma20) / ma20 < 0.01: + ma_pattern = "均线粘合" + elif ma5 > ma10 and ma10 > ma20: + ma_pattern = "多头排列" + elif ma5 < ma10 and ma10 < ma20: + ma_pattern = "空头排列" + elif ma5 > ma10 and ma10 < ma20: + ma_pattern = "金叉形态" + elif ma5 < ma10 and ma10 > ma20: + ma_pattern = "死叉形态" + else: + ma_pattern = "无明显形态" + + data_text += f"均线形态: {ma_pattern}\n" + + # 价格与均线关系 + current_price = df['close'].iloc[-1] + data_text += f"价格相对MA5: {'上方' if current_price > ma5 else '下方'} ({(current_price/ma5-1)*100:.2f}%)\n" + data_text += f"价格相对MA10: {'上方' if current_price > ma10 else '下方'} ({(current_price/ma10-1)*100:.2f}%)\n" + data_text += f"价格相对MA20: {'上方' if current_price > ma20 else '下方'} ({(current_price/ma20-1)*100:.2f}%)\n" + + # 日内超涨超跌分析 + if len(df) >= 20: + # 计算日内振幅 + daily_high = df['high'].iloc[-20:].max() + daily_low = df['low'].iloc[-20:].min() + daily_range = (daily_high - daily_low) / daily_low * 100 + + # 当前价格在日内范围的位置 + current_in_range = (df['close'].iloc[-1] - daily_low) / (daily_high - daily_low) * 100 if (daily_high - daily_low) > 0 else 50 + + data_text += f"日内振幅: {daily_range:.2f}%\n" + data_text += f"价格在日内范围的位置: {current_in_range:.2f}% (0%为日低, 100%为日高)\n" + + # 判断超涨超跌 + if current_in_range > 85: + data_text += "日内状态: 可能超涨\n" + elif current_in_range < 15: + data_text += "日内状态: 可能超跌\n" + else: + data_text += "日内状态: 正常区间\n" + + # 形态识别 + if len(df) >= 20: + # 简单K线形态识别 + recent_k = df.tail(5).copy() + + # 计算实体和影线 + recent_k['body'] = abs(recent_k['close'] - recent_k['open']) + recent_k['upper_shadow'] = recent_k.apply(lambda x: x['high'] - max(x['open'], x['close']), axis=1) + recent_k['lower_shadow'] = recent_k.apply(lambda x: min(x['open'], x['close']) - x['low'], axis=1) + + # 最新K线特征 + latest_k = recent_k.iloc[-1] + prev_k = recent_k.iloc[-2] if len(recent_k) > 1 else None + + data_text += "\nK线形态分析:\n" + + # 判断最新K线类型 + if latest_k['body'] == 0: + k_type = "十字星" + elif latest_k['upper_shadow'] > 2 * latest_k['body'] and latest_k['lower_shadow'] < 0.5 * latest_k['body']: + k_type = "上影线长" + elif latest_k['lower_shadow'] > 2 * latest_k['body'] and latest_k['upper_shadow'] < 0.5 * latest_k['body']: + k_type = "下影线长" + elif latest_k['close'] > latest_k['open'] and latest_k['body'] > np.mean(recent_k['body']): + k_type = "大阳线" + elif latest_k['close'] < latest_k['open'] and latest_k['body'] > np.mean(recent_k['body']): + k_type = "大阴线" + elif latest_k['close'] > latest_k['open']: + k_type = "小阳线" + elif latest_k['close'] < latest_k['open']: + k_type = "小阴线" + else: + k_type = "普通K线" + + data_text += f"最新K线类型: {k_type}\n" + + # 判断简单组合形态 + if prev_k is not None: + if prev_k['close'] < prev_k['open'] and latest_k['close'] > latest_k['open'] and latest_k['open'] <= prev_k['close'] and latest_k['close'] > prev_k['open']: + data_text += "组合形态: 可能构成看涨吞没形态\n" + elif prev_k['close'] > prev_k['open'] and latest_k['close'] < latest_k['open'] and latest_k['open'] >= prev_k['close'] and latest_k['close'] < prev_k['open']: + data_text += "组合形态: 可能构成看跌吞没形态\n" + elif prev_k['close'] < prev_k['open'] and latest_k['close'] > latest_k['open'] and latest_k['body'] > 1.5 * prev_k['body']: + data_text += "组合形态: 可能构成看涨势能增强\n" + elif prev_k['close'] > prev_k['open'] and latest_k['close'] < latest_k['open'] and latest_k['body'] > 1.5 * prev_k['body']: + data_text += "组合形态: 可能构成看跌势能增强\n" + + # 添加订单流特定数据 + data_text += f"\n订单流净值: {recent_data['delta'].iloc[-1]}\n" + data_text += f"订单流累计值: {recent_data['delta累计'].iloc[-1] if 'delta累计' in recent_data.columns else '无数据'}\n" + data_text += f"堆积指标: {recent_data['dj'].iloc[-1]}\n" + + # 添加日均线数据 + data_text += f"日均线: {recent_data['dayma'].iloc[-1] if 'dayma' in recent_data.columns else '无数据'}\n" + + # 添加价格与日均线的关系 + if 'dayma' in recent_data.columns: + price_above_ma = recent_data['close'].iloc[-1] > recent_data['dayma'].iloc[-1] + data_text += f"价格位于日均线: {'上方' if price_above_ma else '下方'}\n" + + # 订单流全面分析 + data_text += "\n订单流详细分析:\n" + + # 计算订单流趋势 + if len(recent_data) >= 5: + delta_values = recent_data['delta'].values + delta_trend = np.mean(np.diff(delta_values)) if len(delta_values) > 1 else 0 + data_text += f"订单流趋势: {'增强中' if delta_trend > 0 else '减弱中'} (变化率: {delta_trend:.2f})\n" + + # 计算订单流强度(使用绝对值的平均值) + delta_strength = np.mean(np.abs(recent_data['delta'].values)) + data_text += f"订单流强度: {delta_strength:.2f}\n" + + # 订单流指标超涨超跌分析 + if len(df) >= 20: + delta_values = df['delta'].iloc[-20:].values + delta_mean = np.mean(delta_values) + delta_std = np.std(delta_values) + current_delta = df['delta'].iloc[-1] + + # Z分数计算 + if delta_std > 0: + delta_z = (current_delta - delta_mean) / delta_std + data_text += f"订单流偏离度(Z分数): {delta_z:.2f}\n" + + if delta_z > 2: + data_text += "订单流状态: 可能超买\n" + elif delta_z < -2: + data_text += "订单流状态: 可能超卖\n" + else: + data_text += "订单流状态: 正常区间\n" + + # 买卖力量对比 + if 'bid_v' in recent_data.columns and 'ask_v' in recent_data.columns: + bid_power = recent_data['bid_v'].mean() + ask_power = recent_data['ask_v'].mean() + power_ratio = bid_power / ask_power if ask_power != 0 else float('inf') + data_text += f"买卖比例: {power_ratio:.2f} (>1买方强势,<1卖方强势)\n" + + # 订单流累计趋势 + if 'delta累计' in recent_data.columns and len(recent_data) >= 2: + cumulative_start = recent_data['delta累计'].iloc[0] + cumulative_end = recent_data['delta累计'].iloc[-1] + cumulative_change = cumulative_end - cumulative_start + data_text += f"累计订单流变化: {cumulative_change:.2f} (从 {cumulative_start:.2f} 到 {cumulative_end:.2f})\n" + + # 订单流波动性 + delta_volatility = np.std(recent_data['delta'].values) + data_text += f"订单流波动性: {delta_volatility:.2f}\n" + + # 订单流与价格相关性 + if len(recent_data) >= 10: # 确保有足够数据计算相关性 + price_changes = recent_data['close'].pct_change().dropna() + delta_changes = recent_data['delta'].iloc[1:].reset_index(drop=True) # 对齐索引 + if len(price_changes) > 0 and len(delta_changes) == len(price_changes): + try: + correlation = np.corrcoef(price_changes, delta_changes)[0, 1] if len(price_changes) > 1 else 0 + data_text += f"订单流与价格相关性: {correlation:.2f}\n" + data_text += f"相关性解读: {'强正相关' if correlation > 0.7 else '正相关' if correlation > 0.3 else '弱相关' if correlation > -0.3 else '负相关' if correlation > -0.7 else '强负相关'}\n" + except: + data_text += "订单流与价格相关性: 计算错误\n" + + # 订单流势能分析(最近几分钟的方向) + recent_deltas = recent_data['delta'].tail(5).values + positive_count = sum(1 for x in recent_deltas if x > 0) + negative_count = sum(1 for x in recent_deltas if x < 0) + data_text += f"最近订单流方向: {'多头主导' if positive_count > negative_count else '空头主导' if positive_count < negative_count else '方向不明'} ({positive_count}正/{negative_count}负)\n" + + # 订单流强弱可视化 + delta_last_10 = recent_data['delta'].tail(10).values # 使用更多数据计算标准差 + delta_std = np.std(delta_last_10) + delta_last_5 = recent_data['delta'].tail(5).values + strength_visual = "" + for val in delta_last_5: + if val > 2 * delta_std: # 大于2个标准差 + strength_visual += "↑↑ " + elif val > 0.5 * delta_std: # 大于0.5个标准差 + strength_visual += "↑ " + elif val < -2 * delta_std: # 小于-2个标准差 + strength_visual += "↓↓ " + elif val < -0.5 * delta_std: # 小于-0.5个标准差 + strength_visual += "↓ " + else: + strength_visual += "→ " + data_text += f"订单流强弱可视化 (最近5分钟): {strength_visual}\n" + data_text += f"当前delta标准差: {delta_std:.2f}\n" + + # 添加最近几条记录的趋势 + data_text += "\n最近几条记录的趋势:\n" + + # 添加最近5条记录的关键指标变化 + for i in range(min(5, len(recent_data))): + idx = -(i+1) + data_text += f"记录 {i+1}: 时间={recent_data['datetime'].iloc[idx]}, 价格={recent_data['close'].iloc[idx]}, " + data_text += f"订单流净值={recent_data['delta'].iloc[idx]}, 堆积={recent_data['dj'].iloc[idx]}\n" + + # 添加当前持仓信息,使用新的止盈止损字典 + data_text += "\n当前持仓状态:\n" + + # 获取该合约的止盈止损信息 + stops = self.stop_order_dict.get(instrument_id, { + 'long': {'position': 0, 'entry_price': 0, 'stop_loss': 0, 'take_profit': 0, 'trailing_stop': 0}, + 'short': {'position': 0, 'entry_price': 0, 'stop_loss': 0, 'take_profit': 0, 'trailing_stop': 0} + }) + + # 获取多头和空头持仓信息 + long_pos = stops.get('long', {}).get('position', 0) + short_pos = stops.get('short', {}).get('position', 0) + + # 判断当前持仓方向 + if long_pos > 0: + data_text += f"持仓方向: 多头\n" + data_text += f"持仓数量: {long_pos}\n" + data_text += f"开仓价格: {stops['long']['entry_price']}\n" + data_text += f"止损价格: {stops['long']['stop_loss']}\n" + data_text += f"止盈价格: {stops['long']['take_profit']}\n" + data_text += f"跟踪止损价: {stops['long']['trailing_stop']}\n" + + # 计算当前盈亏 + current_price = recent_data['close'].iloc[-1] + profit_percent = (current_price - stops['long']['entry_price']) / stops['long']['entry_price'] * 100 + data_text += f"当前盈亏: {profit_percent:.2f}%\n" + elif short_pos > 0: + data_text += f"持仓方向: 空头\n" + data_text += f"持仓数量: {short_pos}\n" + data_text += f"开仓价格: {stops['short']['entry_price']}\n" + data_text += f"止损价格: {stops['short']['stop_loss']}\n" + data_text += f"止盈价格: {stops['short']['take_profit']}\n" + data_text += f"跟踪止损价: {stops['short']['trailing_stop']}\n" + + # 计算当前盈亏 + current_price = recent_data['close'].iloc[-1] + profit_percent = (stops['short']['entry_price'] - current_price) / stops['short']['entry_price'] * 100 + data_text += f"当前盈亏: {profit_percent:.2f}%\n" + else: + data_text += "持仓方向: 空仓\n" + data_text += "持仓数量: 0\n" + + # 添加风险管理参数信息 + data_text += "\n风险管理参数设置:\n" + data_text += f"固定止损百分比: {self.fixed_stop_loss_percent * 100:.2f}%\n" + data_text += f"跟踪止损百分比: {self.trailing_stop_percent * 100:.2f}%\n" + + # 添加交易建议提示 + data_text += "\n请根据以上信息,分析当前市场状态并给出交易建议。需要考虑:\n" + data_text += "1. 当前持仓状态是否合理\n" + data_text += "2. 是否需要调整止损止盈位置\n" + data_text += "3. 是否需要平仓或反手\n" + data_text += "4. 是否适合开新仓\n" + data_text += "5. 是否需要调整跟踪止损百分比参数(范围建议:0.0001-0.001)\n" + data_text += "6. 是否出现抄底摸顶机会\n" + data_text += "7. 是否存在日内波段交易机会\n" + + return data_text + + def update_stop_order_dict(self, instrument_id, direction, position, entry_price=None, stop_loss=None, take_profit=None, trailing_stop=None): + """更新止损止盈信息""" + # 初始化合约的止损止盈字典 + if instrument_id not in self.stop_order_dict: + self.stop_order_dict[instrument_id] = { + 'long': {'position': 0, 'entry_price': 0, 'stop_loss': 0, 'take_profit': 0, 'trailing_stop': 0}, + 'short': {'position': 0, 'entry_price': 0, 'stop_loss': 0, 'take_profit': 0, 'trailing_stop': 0} + } + + # 获取当前值 + current_values = self.stop_order_dict[instrument_id][direction].copy() + + # 更新值 + if position is not None: + self.stop_order_dict[instrument_id][direction]['position'] = position + if entry_price is not None: + self.stop_order_dict[instrument_id][direction]['entry_price'] = entry_price + if stop_loss is not None: + self.stop_order_dict[instrument_id][direction]['stop_loss'] = stop_loss + if take_profit is not None: + self.stop_order_dict[instrument_id][direction]['take_profit'] = take_profit + if trailing_stop is not None: + self.stop_order_dict[instrument_id][direction]['trailing_stop'] = trailing_stop + + # 记录变化值 + updated_values = self.stop_order_dict[instrument_id][direction] + change_log = f"更新{instrument_id} {direction}头寸止损止盈: " + changes = [] + + if position is not None and position != current_values['position']: + changes.append(f"仓位: {current_values['position']} -> {position}") + if entry_price is not None and entry_price != current_values['entry_price']: + changes.append(f"入场价: {current_values['entry_price']} -> {entry_price}") + if stop_loss is not None and stop_loss != current_values['stop_loss']: + changes.append(f"止损价: {current_values['stop_loss']} -> {stop_loss}") + if take_profit is not None and take_profit != current_values['take_profit']: + changes.append(f"止盈价: {current_values['take_profit']} -> {take_profit}") + if trailing_stop is not None and trailing_stop != current_values['trailing_stop']: + changes.append(f"跟踪止损价: {current_values['trailing_stop']} -> {trailing_stop}") + + if changes: + change_log += ", ".join(changes) + STOPLOSS_LOGGER.info(change_log) + + # 保存到文件 + self.save_stop_orders_to_file(instrument_id) + + def save_stop_orders_to_file(self, instrument_id): + """将止盈止损信息保存到文件""" + # 使用完整的合约代码 + symbol = str(instrument_id) + folder_path = "traderdata" + file_path = os.path.join(folder_path, f"{symbol}_stops.json") + + # 如果文件夹不存在则创建 + if not os.path.exists(folder_path): + os.makedirs(folder_path, exist_ok=True) + + # 保存字典到JSON文件 + with open(file_path, 'w') as f: + json.dump(self.stop_order_dict.get(instrument_id, {}), f, indent=4) + + # 获取该合约的止盈止损信息 + stops = self.stop_order_dict.get(instrument_id, { + 'long': {'position': 0, 'entry_price': 0, 'stop_loss': 0, 'take_profit': 0, 'trailing_stop': 0}, + 'short': {'position': 0, 'entry_price': 0, 'stop_loss': 0, 'take_profit': 0, 'trailing_stop': 0} + }) + + # 打印详细信息 + print(f"\n===== 已更新止盈止损信息: {instrument_id} =====") + print(f"多头持仓: {stops['long']['position']} 手") + print(f"多头入场价: {stops['long']['entry_price']}") + print(f"多头止损价: {stops['long']['stop_loss']}") + print(f"多头止盈价: {stops['long']['take_profit']}") + print(f"多头跟踪止损: {stops['long']['trailing_stop']}") + print(f"空头持仓: {stops['short']['position']} 手") + print(f"空头入场价: {stops['short']['entry_price']}") + print(f"空头止损价: {stops['short']['stop_loss']}") + print(f"空头止盈价: {stops['short']['take_profit']}") + print(f"空头跟踪止损: {stops['short']['trailing_stop']}") + print("======================================\n") + + def load_stop_orders_from_file(self, instrument_id): + """从文件加载止盈止损信息""" + # 如果合约ID已经在字典中,直接返回,避免重复加载 + if instrument_id in self.stop_order_dict: + return True + + # 使用完整的合约代码 + symbol = str(instrument_id) + folder_path = "traderdata" + file_path = os.path.join(folder_path, f"{symbol}_stops.json") + + if os.path.exists(file_path): + try: + with open(file_path, 'r') as f: + stops_data = json.load(f) + + # 更新字典 + self.stop_order_dict[instrument_id] = stops_data + print(f"首次加载止盈止损信息: {instrument_id}") + return True + except Exception as e: + print(f"加载止盈止损信息失败: {e}") + + # 如果文件不存在,初始化空字典结构 + if instrument_id not in self.stop_order_dict: + self.stop_order_dict[instrument_id] = { + 'long': {'position': 0, 'entry_price': 0, 'stop_loss': 0, 'take_profit': 0, 'trailing_stop': 0}, + 'short': {'position': 0, 'entry_price': 0, 'stop_loss': 0, 'take_profit': 0, 'trailing_stop': 0} + } + print(f"初始化止盈止损结构: {instrument_id}") + + return False + + def check_stop_conditions(self, data): + """检查是否满足止盈止损条件""" + instrument_id = data['InstrumentID'].decode() + + # 如果该合约不在止盈止损字典中,直接返回 + if instrument_id not in self.stop_order_dict: + return + + current_bid = float(data['BidPrice1']) # 当前买价 + current_ask = float(data['AskPrice1']) # 当前卖价 + + stops = self.stop_order_dict[instrument_id] + + # 检查多头止盈止损 + if stops['long']['position'] > 0: + entry_price = stops['long']['entry_price'] # 获取开仓价 + + # 检查止损 + if stops['long']['stop_loss'] > 0 and current_bid <= stops['long']['stop_loss']: + print(f"触发多头止损: {instrument_id}, 价格: {current_bid}, 止损价: {stops['long']['stop_loss']}") + self.insert_order(data['ExchangeID'], data['InstrumentID'], current_bid-self.py, + stops['long']['position'], b'1', b'3') + # 清空多头持仓信息 + self.clear_position_info(instrument_id, 'long') + self.pos = 0 # 更新全局持仓状态 + + # 检查跟踪止损 - 确保只在价格高于开仓价且低于跟踪止损价时触发 + elif stops['long']['trailing_stop'] > 0 and current_bid < stops['long']['trailing_stop'] and current_bid > entry_price: + print(f"触发多头跟踪止损: {instrument_id}, 价格: {current_bid}, 跟踪止损价: {stops['long']['trailing_stop']}, 开仓价: {entry_price}") + self.insert_order(data['ExchangeID'], data['InstrumentID'], current_bid-self.py, + stops['long']['position'], b'1', b'3') + # 清空多头持仓信息 + self.clear_position_info(instrument_id, 'long') + self.pos = 0 # 更新全局持仓状态 + + # 检查止盈 + elif stops['long']['take_profit'] > 0 and current_bid >= stops['long']['take_profit']: + print(f"触发多头止盈: {instrument_id}, 价格: {current_bid}, 止盈价: {stops['long']['take_profit']}") + self.insert_order(data['ExchangeID'], data['InstrumentID'], current_bid-self.py, + stops['long']['position'], b'1', b'3') + # 清空多头持仓信息 + self.clear_position_info(instrument_id, 'long') + self.pos = 0 # 更新全局持仓状态 + + # 更新跟踪止损价 - 严格限制只在价格高于开仓价时更新 + elif current_bid > entry_price and stops['long']['trailing_stop'] > 0: + # 只有当前价格比之前设置的跟踪止损价高一定幅度时才更新 + new_trailing_stop = current_bid * (1 - self.trailing_stop_percent) + + # 判断是否应该更新跟踪止损价 + should_update = False + + # 条件1: 新的跟踪止损价必须高于当前的跟踪止损价(跟踪止损上移) + if new_trailing_stop > stops['long']['trailing_stop']: + # 条件2: 如果存在止损价(非0),则新的跟踪止损价不应该触及人工设置的止损价 + if stops['long']['stop_loss'] == 0 or new_trailing_stop < stops['long']['stop_loss']: + should_update = True + + if should_update: + self.update_stop_order_dict(instrument_id, 'long', None, None, None, None, new_trailing_stop) + print(f"更新多头跟踪止损: {instrument_id}, 新跟踪止损价: {new_trailing_stop}, 开仓价: {entry_price}") + + # 检查空头止盈止损 + if stops['short']['position'] > 0: + entry_price = stops['short']['entry_price'] # 获取开仓价 + + # 检查止损 + if stops['short']['stop_loss'] > 0 and current_ask >= stops['short']['stop_loss']: + print(f"触发空头止损: {instrument_id}, 价格: {current_ask}, 止损价: {stops['short']['stop_loss']}") + self.insert_order(data['ExchangeID'], data['InstrumentID'], current_ask+self.py, + stops['short']['position'], b'0', b'3') + # 清空空头持仓信息 + self.clear_position_info(instrument_id, 'short') + self.pos = 0 # 更新全局持仓状态 + + # 检查跟踪止损 - 确保只在价格低于开仓价且高于跟踪止损价时触发 + elif stops['short']['trailing_stop'] > 0 and current_ask > stops['short']['trailing_stop'] and current_ask < entry_price: + print(f"触发空头跟踪止损: {instrument_id}, 价格: {current_ask}, 跟踪止损价: {stops['short']['trailing_stop']}, 开仓价: {entry_price}") + self.insert_order(data['ExchangeID'], data['InstrumentID'], current_ask+self.py, + stops['short']['position'], b'0', b'3') + # 清空空头持仓信息 + self.clear_position_info(instrument_id, 'short') + self.pos = 0 # 更新全局持仓状态 + + # 检查止盈 + elif stops['short']['take_profit'] > 0 and current_ask <= stops['short']['take_profit']: + print(f"触发空头止盈: {instrument_id}, 价格: {current_ask}, 止盈价: {stops['short']['take_profit']}") + self.insert_order(data['ExchangeID'], data['InstrumentID'], current_ask+self.py, + stops['short']['position'], b'0', b'3') + # 清空空头持仓信息 + self.clear_position_info(instrument_id, 'short') + self.pos = 0 # 更新全局持仓状态 + + # 更新跟踪止损价 - 严格限制只在价格低于开仓价时更新 + elif current_ask < entry_price and stops['short']['trailing_stop'] > 0: + # 只有当前价格比之前设置的跟踪止损价低一定幅度时才更新 + new_trailing_stop = current_ask * (1 + self.trailing_stop_percent) + + # 判断是否应该更新跟踪止损价 + should_update = False + + # 条件1: 新的跟踪止损价必须低于当前的跟踪止损价(跟踪止损下移)或当前跟踪止损价为0 + if new_trailing_stop < stops['short']['trailing_stop'] or stops['short']['trailing_stop'] == 0: + # 条件2: 如果存在止损价(非0),则新的跟踪止损价不应该触及人工设置的止损价 + if stops['short']['stop_loss'] == 0 or new_trailing_stop > stops['short']['stop_loss']: + should_update = True + + if should_update: + self.update_stop_order_dict(instrument_id, 'short', None, None, None, None, new_trailing_stop) + print(f"更新空头跟踪止损: {instrument_id}, 新跟踪止损价: {new_trailing_stop}, 开仓价: {entry_price}") + + #保存数据 + + def clear_position_info(self, instrument_id, direction): + """ + 清空指定合约和方向的持仓信息 + + Args: + instrument_id: 合约ID + direction: 方向 'long' 或 'short' 或 'all' + """ + # 确保合约ID在字典中存在 + if instrument_id not in self.stop_order_dict: + return + + print(f"开始清空{instrument_id}的{direction}持仓信息") + if direction == 'long' or direction == 'all': + # 清空多头持仓信息 + self.stop_order_dict[instrument_id]['long'] = { + 'position': 0, + 'entry_price': 0, + 'stop_loss': 0, + 'take_profit': 0, + 'trailing_stop': 0 + } + # 兼容旧代码 + if direction == 'long': + self.long_trailing_stop_price = 0 + self.sl_long_price = 0 + + if direction == 'short' or direction == 'all': + # 清空空头持仓信息 + self.stop_order_dict[instrument_id]['short'] = { + 'position': 0, + 'entry_price': 0, + 'stop_loss': 0, + 'take_profit': 0, + 'trailing_stop': 0 + } + # 兼容旧代码 + if direction == 'short': + self.short_trailing_stop_price = 0 + self.sl_shor_price = 0 + + # 同步全局持仓状态 + if direction == 'all': + self.pos = 0 + self.long_trailing_stop_price = 0 + self.short_trailing_stop_price = 0 + self.sl_long_price = 0 + self.sl_shor_price = 0 + + # 保存到文件 + try: + self.save_stop_orders_to_file(instrument_id) + self.save_to_csv(instrument_id) + print(f"已成功清空{instrument_id}的{direction}持仓信息并保存") + except Exception as e: + print(f"清空持仓信息时出错: {e}") + +# 修改call_deepseek_model函数,移除JSON格式输出的要求,改为从普通文本响应中提取交易信号。 +def call_deepseek_model(data_df, trader_instance, max_retries=2): + """ + 调用qwq-32b大模型分析订单流数据 + + Args: + data_df: 包含订单流数据的DataFrame + trader_instance: MyTrader实例,用于访问持仓信息 + max_retries: 最大重试次数 + + Returns: + dict: 包含交易信号的字典 + """ + # 直接从环境变量获取API密钥 + api_key = GLOBAL_LLM_CONFIG.get('api_key') + base_url = GLOBAL_LLM_CONFIG.get('base_url') + model_name = GLOBAL_LLM_CONFIG.get('model_name') + + # 检查API密钥是否为空 + if not api_key: + print("错误: API密钥未设置,请在main函数中配置GLOBAL_LLM_CONFIG['api_key']") + return {"action": "不操作", "reason": "API密钥未设置", "confidence": 0, "stop_loss": 0, "take_profit": 0} + + # 将DataFrame转换为可读性好的文本,传递trader_instance + data_text = trader_instance.format_data_for_llm(data_df) + + # 构建提示词 + prompt = f""" + 作为专注于趋势交易的期货交易员,基于以下市场数据做出交易决策: + + {data_text} + + 请重点考虑以下关键因素: + 1. 均线系统(5、10、20均线)的排列状态和金叉死叉信号 + 2. 价格是否处于明确的上升或下降通道中 + 3. 关键阻力位和支撑位的突破情况及其确认 + 4. 成交量是否配合价格趋势(上涨时放量,下跌时同样放量) + 5. 动量指标(MACD、KDJ等)的走势和信号 + 6. 订单流趋势与主力资金方向的一致性 + 7. 市场多空力量对比的持续性变化 + 8. 当前趋势的强度与持续时间评估 + + 【风险控制原则】: + - 严格控制每笔交易亏损不超过本金的1% + - 趋势交易的止损位应设置在次级回调位或关键技术位之下,通常为开仓价的0.5%-0.1% + - 使用移动止损机制跟踪趋势发展,锁定利润 + - 避免在盘整区间内频繁交易,等待明确的突破信号 + + 请根据市场状态和持仓情况,给出明确的交易指令: + 1. 交易方向: 不操作/开多/开空/平多/平空/平多开空/平空开多 + 2. 执行理由: 详细说明趋势特征、突破信号、动量变化和持续性评估 + 3. 置信度: 1-10的数字,反映趋势信号的清晰度,必须是整数 + 4. 止损价: 明确的止损价格(必须是数字),设置在关键支撑/阻力位附近 + 5. 止盈价: 明确的首个止盈目标(必须是数字),应至少是止损距离的1.5倍 + 6. 跟踪止损百分比: 0.0001-0.001之间的数字,用于设置移动止损追踪趋势 + + 请按以下格式返回交易决策,格式必须严格匹配: + action: 不操作/开多/开空/平多/平空/平多开空/平空开多 + reason: 交易理由 + confidence: 置信度(1-10) + stop_loss: 止损价 + take_profit: 止盈价 + trailing_percent: 跟踪止损百分比(0.0001-0.001) + """ + + system_prompt = {"role": "system", + "content": "你是一位专注于趋势交易的期货交易员,擅长识别和追踪强势趋势。你的交易风格注重动量和突破信号,善于在确认趋势后顺势而为,合理管理风险的同时最大化捕捉趋势利润。你特别关注均线系统、趋势线、成交量确认和动量指标,能精准判断趋势的强度和持续性。你擅长使用移动止损保护利润,在趋势延续时持有头寸,在趋势减弱时及时退出。请根据指定格式返回交易决策。"} + + # 添加重试机制 + retries = 0 + while retries <= max_retries: + try: + # 如果不是第一次尝试,输出重试信息 + if retries > 0: + print(f"正在进行第 {retries} 次重试...") + + # 调试信息 + print(f"使用API参数: base_url={base_url}, model={model_name}") + + # 添加明显的提示信息,表示正在调用大模型API + print("\n============================================") + print("【正在调用大模型API进行交易分析,请稍候...】") + print("============================================\n") + + # 记录开始时间 + api_start_time = time.time() + + # 使用OpenAI客户端格式调用API + client = OpenAI(api_key=api_key, base_url=base_url) + + # 发起流式请求 + response = client.chat.completions.create( + model=model_name, + messages=[ + system_prompt, + {"role": "user", "content": prompt} + ], + temperature=0.1, + stream=False, # 不启用流式模式 + max_tokens=8192, + timeout=60 + ) + + # 提取模型响应内容 + model_response = response.choices[0].message.content + + # 计算耗时 + api_elapsed = time.time() - api_start_time + print(f"\n\n模型响应总耗时: {api_elapsed:.2f}秒") + print("完整响应前100字符: " + model_response[:100] + "...") + + # 添加明显的提示信息,表示API调用已完成 + print("\n============================================") + print("【大模型API调用完成】") + print("============================================\n") + + # 从文本中解析出交易信号 + try: + trading_signal = parse_trading_signal(model_response) + return trading_signal + except Exception as parse_err: + print(f"解析模型响应出错: {parse_err}") + # 尝试从自由文本中提取关键信息 + return extract_trading_signal_from_text(model_response) + + except Exception as e: + retries += 1 + if retries <= max_retries: + print(f"调用大模型API出错: {e}") + print(f"将在3秒后重试...") + time.sleep(3) # 等待3秒后重试 + else: + print(f"已达到最大重试次数 ({max_retries}),调用大模型API失败") + print(f"错误详情: {e}") + print("\n请检查以下几点:") + print("1. API密钥格式是否正确,应以'sk-'开头") + print("2. 确认已安装最新版本的openai库: pip install --upgrade openai") + print("3. 确认您的API密钥对应的模型是否为deepseek-reasoner") + # 返回默认的不操作信号 + return {"action": "不操作", "reason": f"API调用失败: {str(e)[:100]}", "confidence": 0, "stop_loss": 0, "take_profit": 0} + + # 如果所有重试都失败了,返回默认值 + return {"action": "不操作", "reason": "API调用重试耗尽", "confidence": 0, "stop_loss": 0, "take_profit": 0} + +def parse_trading_signal(text): + """ + 从文本格式的模型响应中解析出交易信号 + + Args: + text: 模型响应文本 + + Returns: + dict: 包含交易信号的字典 + """ + lines = text.strip().split('\n') + trading_signal = {} + + for line in lines: + if ':' in line: + key, value = line.split(':', 1) + key = key.strip().lower() + value = value.strip() + + if key == 'action': + trading_signal['action'] = value + elif key == 'reason': + trading_signal['reason'] = value + elif key == 'confidence': + try: + trading_signal['confidence'] = int(value) + except ValueError: + # 尝试从文本中提取数字 + import re + match = re.search(r'\d+', value) + if match: + trading_signal['confidence'] = int(match.group()) + else: + trading_signal['confidence'] = 0 + elif key == 'stop_loss': + try: + trading_signal['stop_loss'] = float(value) + except ValueError: + # 尝试从文本中提取数字 + import re + match = re.search(r'\d+(\.\d+)?', value) + if match: + trading_signal['stop_loss'] = float(match.group()) + else: + trading_signal['stop_loss'] = 0 + elif key == 'take_profit': + try: + trading_signal['take_profit'] = float(value) + except ValueError: + # 尝试从文本中提取数字 + import re + match = re.search(r'\d+(\.\d+)?', value) + if match: + trading_signal['take_profit'] = float(match.group()) + else: + trading_signal['take_profit'] = 0 + elif key == 'trailing_percent': + try: + value_float = float(value) + # 确保值在合理范围内 0.0001-0.001 + if 0.0001<= value_float <= 0.001: + trading_signal['trailing_percent'] = value_float + else: + # 设置为默认值 + trading_signal['trailing_percent'] = 0.0005 + except ValueError: + trading_signal['trailing_percent'] = 0.0005 + + # 检查是否有缺失的字段,如果有,设置默认值 + if 'action' not in trading_signal: + trading_signal['action'] = '不操作' + if 'reason' not in trading_signal: + trading_signal['reason'] = '未提供理由' + if 'confidence' not in trading_signal: + trading_signal['confidence'] = 0 + if 'stop_loss' not in trading_signal: + trading_signal['stop_loss'] = 0 + if 'take_profit' not in trading_signal: + trading_signal['take_profit'] = 0 + if 'trailing_percent' not in trading_signal: + trading_signal['trailing_percent'] = 0.0005 # 修改默认值 + + return trading_signal + +def extract_trading_signal_from_text(text): + """ + 从自由格式文本中尝试提取交易信号 + + Args: + text: 模型响应文本 + + Returns: + dict: 包含交易信号的字典 + """ + # 默认交易信号 + trading_signal = { + "action": "不操作", + "reason": "无法解析模型响应", + "confidence": 0, + "stop_loss": 0, + "take_profit": 0, + "trailing_percent": 0 # 更新默认的跟踪止损百分比 + } + + # 尝试判断交易方向 + text_lower = text.lower() + if "平多开空" in text_lower: + trading_signal["action"] = "平多开空" + elif "平空开多" in text_lower: + trading_signal["action"] = "平空开多" + elif "开多" in text_lower: + trading_signal["action"] = "开多" + elif "开空" in text_lower: + trading_signal["action"] = "开空" + elif "平多" in text_lower: + trading_signal["action"] = "平多" + elif "平空" in text_lower: + trading_signal["action"] = "平空" + elif "不操作" in text_lower or "观望" in text_lower: + trading_signal["action"] = "不操作" + + # 尝试从文本中提取置信度 + import re + confidence_matches = re.findall(r'置信度[::]\s*(\d+)', text_lower) + if confidence_matches: + try: + trading_signal["confidence"] = int(confidence_matches[0]) + except ValueError: + pass + + # 尝试提取止损价 + stop_loss_matches = re.findall(r'止损价[::]\s*(\d+(\.\d+)?)', text_lower) + if stop_loss_matches: + try: + trading_signal["stop_loss"] = float(stop_loss_matches[0][0]) + except ValueError: + pass + + # 尝试提取止盈价 + take_profit_matches = re.findall(r'止盈价[::]\s*(\d+(\.\d+)?)', text_lower) + if take_profit_matches: + try: + trading_signal["take_profit"] = float(take_profit_matches[0][0]) + except ValueError: + pass + + # 尝试提取跟踪止损百分比 + trailing_matches = re.findall(r'跟踪止损百分比[::]\s*(\d+(\.\d+)?)', text_lower) + if not trailing_matches: + trailing_matches = re.findall(r'跟踪百分比[::]\s*(\d+(\.\d+)?)', text_lower) + + if trailing_matches: + try: + trailing_value = float(trailing_matches[0][0]) + # 判断是否为百分比格式 + if trailing_value >= 0.5 and trailing_value <= 10: + trading_signal["trailing_percent"] = trailing_value / 100 + else: + trading_signal["trailing_percent"] = trailing_value + except ValueError: + pass + + # 提取理由 + reason_matches = re.findall(r'理由[::]\s*(.*?)(?=\n|$)', text_lower) + if reason_matches: + trading_signal["reason"] = reason_matches[0] + + return trading_signal + +# 修改run_trader函数,改为接收统一的配置字典 +def run_trader(broker_id, td_server, investor_id, password, app_id, auth_code, md_queue=None, page_dir='', private_resume_type=2, public_resume_type=2, config=None): + # 设置全局变量 + global GLOBAL_LLM_CONFIG + + # 如果传入了配置字典,直接使用 + if config: + # 使用deepcopy避免潜在的引用问题 + import copy + GLOBAL_LLM_CONFIG = copy.deepcopy(config) + else: + # 确保有默认值 + if 'bar_resample_rule' not in GLOBAL_LLM_CONFIG: + GLOBAL_LLM_CONFIG['bar_resample_rule'] = '1T' + if 'load_history' not in GLOBAL_LLM_CONFIG: + GLOBAL_LLM_CONFIG['load_history'] = False + if 'history_rows' not in GLOBAL_LLM_CONFIG: + GLOBAL_LLM_CONFIG['history_rows'] = 1000 + if 'trader_rows' not in GLOBAL_LLM_CONFIG: + GLOBAL_LLM_CONFIG['trader_rows'] = 10 + + # # 创建合适的日志目录,使用os.path.join确保路径分隔符正确 + # log_dir = os.path.join('.', 'log') + # if not os.path.exists(log_dir): + # os.makedirs(log_dir, exist_ok=True) + + # 使用位置参数调用MyTrader初始化,因为Cython类不支持关键字参数 + my_trader = MyTrader( + broker_id, + td_server, + investor_id, + password, + app_id, + auth_code, + md_queue, + page_dir, # 使用修复后的日志目录路径 + private_resume_type, + public_resume_type + ) + + # 设置历史数据加载参数 + my_trader.load_history = GLOBAL_LLM_CONFIG['load_history'] + my_trader.history_rows = GLOBAL_LLM_CONFIG['history_rows'] + my_trader.trader_rows = GLOBAL_LLM_CONFIG['trader_rows'] + my_trader.Join() + +def ceshiapi(api_key): + # 测试API连接 + print(f"测试API连接,使用密钥: {api_key[:5]}...{api_key[-5:]}") + try: + client = OpenAI(api_key=api_key, base_url=GLOBAL_LLM_CONFIG['base_url'] ) + response = client.chat.completions.create( + model=GLOBAL_LLM_CONFIG['model_name'], + messages=[ + {"role": "system", "content": "你是一个助手"}, + {"role": "user", "content": "测试"} + ], + stream=False, # 新增此行 + max_tokens=10 + ) + print(f"API连接测试成功") + except Exception as e: + print(f"API连接测试失败: {e}") + import traceback + traceback.print_exc() + +def clean_log_directory(log_dir="./log", timeout_seconds=5): + """ + 清理日志目录内的所有文件和子目录,具有超时机制和健壮的异常处理 + + 参数: + log_dir (str): 日志目录路径,默认为"./log" + timeout_seconds (int): 清理操作的最大等待时间(秒),默认为5秒 + + 返回: + bool: 清理操作是否成功完成(未超时且无严重错误) + """ + + print(f"开始清理日志目录: {log_dir}") + success = True + + if os.path.exists(log_dir): + # 设置超时机制,避免长时间阻塞 + start_time = time.time() + + try: + # 遍历并删除log目录下的所有文件和子目录 + for item in os.listdir(log_dir): + # 检查是否超时 + if time.time() - start_time > timeout_seconds: + print(f"清理操作超过{timeout_seconds}秒,中断清理") + success = False + break + + item_path = os.path.join(log_dir, item) + try: + if os.path.isfile(item_path): + os.unlink(item_path) + elif os.path.isdir(item_path): + shutil.rmtree(item_path, ignore_errors=True) + print(f"已清理: {item_path}") + except Exception as e: + print(f"清理 {item_path} 时出错: {e}") + # 记录错误但继续处理其他文件 + except Exception as e: + print(f"清理log目录时出现意外错误: {e}") + success = False + else: + # 如果log目录不存在,则创建它 + try: + os.makedirs(log_dir) + print(f"创建日志目录: {log_dir}") + except Exception as e: + print(f"创建日志目录失败: {e}") + success = False + + if success: + print(f"日志目录清理完成: {log_dir}") + else: + print(f"日志目录清理未完全完成: {log_dir}") + + return success + +if __name__ == '__main__': + #公众号:松鼠Quant + #主页:www.quant789.com + #本策略仅作学习交流使用,实盘交易盈亏投资者个人负责!!! + #版权归松鼠Quant所有,禁止转发、转卖源码违者必究。 + + # 清理日志目录 + clean_log_directory(log_dir="./log", timeout_seconds=10) # 可以调整超时时间 + + + #============================================================个人填写信息区============================================================# + + # 配置大模型参数 o3 代理地址: https://2233.ai/i/9ONWNBDK + api_key = "" + GLOBAL_LLM_CONFIG['api_key'] = api_key + GLOBAL_LLM_CONFIG['base_url'] = "https://api.gptsapi.net/v1" + GLOBAL_LLM_CONFIG['model_name'] = "o3-mini-2025-01-31" + ceshiapi(api_key) # 测试API连接 + + # 历史数据加载配置 + GLOBAL_LLM_CONFIG['load_history'] = True + GLOBAL_LLM_CONFIG['history_rows'] = 50 + GLOBAL_LLM_CONFIG['trader_rows'] = 10 + GLOBAL_LLM_CONFIG['bar_resample_rule'] = '3T' # 3分钟K线 + + # 模拟账户信息 + investor_id = '' # simnow账户,注意是登录账户的ID,SIMNOW个人首页查看 + password = '' # simnow密码 + server_name = '电信1' # 电信1、电信2、移动、TEST、N视界 + subscribe_list = [b'au2506'] # 合约列表 目前只支持单品种 + + #============================================================个人填写信息区============================================================# + + # 创建临时工作目录(在log文件夹内) + timestamp = int(time.time()) + temp_md_dir = f"./log/{investor_id}_md_{timestamp}" + temp_td_dir = f"./log/{investor_id}_td_{timestamp}" + + #用simnow模拟,不要忘记屏蔽下方实盘的future_account字典 + future_account = get_simulate_account( + investor_id=investor_id, + password=password, + server_name=server_name, + subscribe_list=subscribe_list, + md_flow_path=temp_md_dir, + td_flow_path=temp_td_dir, + ) + + # #实盘用这个,不要忘记屏蔽上方simnow的future_account字典 + # future_account = FutureAccount( + # broker_id='', # 期货公司BrokerID + # server_dict={'TDServer': "ip:port", 'MDServer': 'ip:port'}, # TDServer为交易服务器,MDServer为行情服务器。服务器地址格式为"ip:port。" + # reserve_server_dict={}, # 备用服务器地址 + # investor_id='', # 账户 + # password='', # 密码 + # app_id='simnow_client_test', # 认证使用AppID + # auth_code='0000000000000000', # 认证使用授权码 + # subscribe_list=[b'au2506'], # 订阅合约列表 + # md_flow_path=temp_md_dir, # MdApi流文件存储地址,默认MD_LOCATION + # td_flow_path=temp_td_dir, # TraderApi流文件存储地址,默认TD_LOCATION + # ) + + print('开始', len(future_account.subscribe_list)) + # 共享队列 + share_queue = Queue(maxsize=200) + + # 行情进程 + md_process = Process(target=run_tick_engine, args=(future_account, [share_queue])) + + # 使用深拷贝创建一个完全独立的配置副本 + import copy + config_copy = copy.deepcopy(GLOBAL_LLM_CONFIG) + + # 交易进程 + trader_process = Process(target=run_trader, args=( + future_account.broker_id, + future_account.server_dict['TDServer'], + future_account.investor_id, + future_account.password, + future_account.app_id, + future_account.auth_code, + share_queue, + temp_td_dir, + 2, # private_resume_type + 2, # public_resume_type + config_copy, + )) + + md_process.start() + trader_process.start() + + md_process.join() + trader_process.join() diff --git a/1.交易策略/999.其他策略/4.松鼠SF20_基于LLM的订单流日内交易策略/使用文档/4.02版本_new/定时启动.py b/1.交易策略/999.其他策略/4.松鼠SF20_基于LLM的订单流日内交易策略/使用文档/4.02版本_new/定时启动.py new file mode 100644 index 0000000..02f2c14 --- /dev/null +++ b/1.交易策略/999.其他策略/4.松鼠SF20_基于LLM的订单流日内交易策略/使用文档/4.02版本_new/定时启动.py @@ -0,0 +1,53 @@ +import subprocess +import schedule +import time +from datetime import datetime + +# 定义要启动的文件 +files_to_run = ['专享策略20_o3mini.py'] + + +def run_scripts(): + print("启动程序...") + for file in files_to_run: + time.sleep(1) + # 使用subprocess模块运行命令 + subprocess.Popen(['start', 'cmd', '/k', 'python', file], shell=True) + print(file) + print(datetime.now(),'程序重新启动完成,等待明天关闭重启') + + +def close_scripts(): + print("关闭程序...") + # 通过创建一个包含关闭指定窗口命令的批处理文件来关闭CMD窗口 + def close_specific_cmd_window(cmd_window_title): + with open("close_cmd_window.bat", "w") as batch_file: + batch_file.write(f'@echo off\nfor /f "tokens=2 delims=," %%a in (\'tasklist /v /fo csv ^| findstr /i "{cmd_window_title}"\') do taskkill /pid %%~a') + + # 运行批处理文件 + subprocess.run("close_cmd_window.bat", shell=True) + + + # 循环关闭所有脚本对应的CMD窗口 + for title in files_to_run: + close_specific_cmd_window(title) + print(datetime.now(),'已关闭程序,等待重新运行程序') + + + +# 设置定时任务,关闭程序 +schedule.every().day.at("15:20").do(close_scripts) +schedule.every().day.at("02:45").do(close_scripts) + +# 设置定时任务,启动程序 +schedule.every().day.at("08:55").do(run_scripts) +schedule.every().day.at("20:55").do(run_scripts) + + + +# 保持脚本运行,等待定时任务触发 + #zzg_quant +while True: + schedule.run_pending() + time.sleep(1) + #zzg_quant diff --git a/1.交易策略/999.其他策略/4.松鼠SF20_基于LLM的订单流日内交易策略/使用文档/4.14版本_new/4.14更新日志.txt b/1.交易策略/999.其他策略/4.松鼠SF20_基于LLM的订单流日内交易策略/使用文档/4.14版本_new/4.14更新日志.txt new file mode 100644 index 0000000..9900a0b --- /dev/null +++ b/1.交易策略/999.其他策略/4.松鼠SF20_基于LLM的订单流日内交易策略/使用文档/4.14版本_new/4.14更新日志.txt @@ -0,0 +1,5 @@ +4.14更新: +1.修复收盘清仓时间段开仓问题。 +2.策略参数填写区增加下单手数变量。 +3.增加实盘代码的个人信息字典。 +4.取消置信度的判断。 \ No newline at end of file diff --git a/1.交易策略/999.其他策略/4.松鼠SF20_基于LLM的订单流日内交易策略/使用文档/4.14版本_new/vip20_orderflow.py b/1.交易策略/999.其他策略/4.松鼠SF20_基于LLM的订单流日内交易策略/使用文档/4.14版本_new/vip20_orderflow.py new file mode 100644 index 0000000..395d462 --- /dev/null +++ b/1.交易策略/999.其他策略/4.松鼠SF20_基于LLM的订单流日内交易策略/使用文档/4.14版本_new/vip20_orderflow.py @@ -0,0 +1,2596 @@ +''' +#公众号:松鼠Quant +#主页:www.quant789.com +#本策略仅作学习交流使用,实盘交易盈亏投资者个人负责!!! +#版权归松鼠Quant所有,禁止转发、转卖源码违者必究。 + +该代码的主要目的是处理Tick数据并生成交易信号。代码中定义了一个tickcome函数,它接收到Tick数据后会进行一系列的处理,包括构建Tick字典、更新上一个Tick的成交量、保存Tick数据、生成K线数据等。其中涉及到的一些函数有: + +on_tick(tick): 处理单个Tick数据,根据Tick数据生成K线数据。 +tickdata(df, symbol): 处理Tick数据,生成K线数据。 +orderflow_df_new(df_tick, df_min, symbol): 处理Tick和K线数据,生成订单流数据。 +GetOrderFlow_dj(kData): 计算订单流的信号指标。 +除此之外,代码中还定义了一个MyTrader类,继承自TraderApiBase,用于实现交易相关的功能。 +#公众号:松鼠Quant +#主页:www.quant789.com +#本策略仅作学习交流使用,实盘交易盈亏投资者个人负责!!! +#版权归松鼠Quant所有,禁止转发、转卖源码违者必究。 +''' +from multiprocessing import Process, Queue +from AlgoPlus.CTP.MdApi import run_tick_engine +from AlgoPlus.CTP.FutureAccount import get_simulate_account +from AlgoPlus.CTP.FutureAccount import FutureAccount +from AlgoPlus.CTP.TraderApiBase import TraderApiBase +from AlgoPlus.ta.time_bar import tick_to_bar +import pandas as pd +from datetime import datetime, timedelta +from datetime import time as s_time +import operator +import time +import numpy as np +import os +import re +import json +import requests # 添加requests库用于API调用 +from openai import OpenAI # 导入OpenAI客户端 +import threading +from queue import Queue as ThreadQueue +import warnings +warnings.filterwarnings("ignore", category=FutureWarning) +import copy +import math +import shutil +import re # 新增 +import logging # 新增 +from logging.handlers import RotatingFileHandler # 新增 + + +# 在文件顶部定义全局变量 +tickdatadict = {} # 存储Tick数据的字典 +quotedict = {} # 存储行情数据的字典 +ofdatadict = {} # 存储K线数据的字典 +trader_df = pd.DataFrame({}) # 存储交易数据的DataFrame对象 +previous_volume = {} # 上一个Tick的成交量 +tsymbollist={} +# 全局LLM配置变量 +GLOBAL_LLM_CONFIG = {} # 全局大模型配置参数 +# 全局交易信号队列,用于存储AI模型生成的交易信号 +AI_SIGNAL_QUEUE = ThreadQueue() +# 标记是否有AI线程正在运行 +AI_THREAD_RUNNING = False +# 不再需要单独的K线时间粒度全局变量,它已经被整合到GLOBAL_LLM_CONFIG中 + +def setup_logging(log_folder='logs'): + # 确保日志文件夹存在 + if not os.path.exists(log_folder): + os.makedirs(log_folder) + + # 创建日志格式 + formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s') + + # ==== 修复点:所有FileHandler显式设置encoding='utf-8' ==== + + # AI分析日志 + ai_logger = logging.getLogger('ai_analysis') + ai_logger.setLevel(logging.INFO) + ai_file_handler = RotatingFileHandler( + os.path.join(log_folder, 'ai_analysis.log'), + maxBytes=10 * 1024 * 1024, # 10MB + backupCount=5, + encoding='utf-8' # 关键修复:强制UTF-8编码 + ) + ai_file_handler.setFormatter(formatter) + ai_logger.addHandler(ai_file_handler) + + # 交易信号日志 + signal_logger = logging.getLogger('trading_signals') + signal_logger.setLevel(logging.INFO) + signal_file_handler = RotatingFileHandler( + os.path.join(log_folder, 'trading_signals.log'), + maxBytes=10 * 1024 * 1024, + backupCount=5, + encoding='utf-8' # 关键修复 + ) + signal_file_handler.setFormatter(formatter) + signal_logger.addHandler(signal_file_handler) + + # 止损止盈日志 + stoploss_logger = logging.getLogger('stoploss') + stoploss_logger.setLevel(logging.INFO) + stoploss_file_handler = RotatingFileHandler( + os.path.join(log_folder, 'stoploss.log'), + maxBytes=10 * 1024 * 1024, + backupCount=5, + encoding='utf-8' # 关键修复 + ) + stoploss_file_handler.setFormatter(formatter) + stoploss_logger.addHandler(stoploss_file_handler) + + return ai_logger, signal_logger, stoploss_logger + +# 全局日志记录器 +AI_LOGGER, SIGNAL_LOGGER, STOPLOSS_LOGGER = setup_logging() + +def tickcome(md_queue): + global previous_volume + + data=md_queue + instrument_id = data['InstrumentID'].decode() # 品种代码 + ActionDay = data['ActionDay'].decode() # 交易日日期 + update_time = data['UpdateTime'].decode() # 更新时间 + #zzg_quant + update_millisec = str(data['UpdateMillisec']) # 更新毫秒数 + created_at = ActionDay[:4] + '-' + ActionDay[4:6] + '-' + ActionDay[6:] + ' ' + update_time + '.' + update_millisec #创建时间 + # 构建tick字典 + tick = { + 'symbol': instrument_id, # 品种代码和交易所ID + 'created_at':datetime.strptime(created_at, "%Y-%m-%d %H:%M:%S.%f"), + #'created_at': created_at, # 创建时间 + 'price': float(data['LastPrice']), # 最新价 + 'last_volume': int(data['Volume']) - previous_volume.get(instrument_id, 0) if previous_volume.get(instrument_id, 0) != 0 else 0, # 瞬时成交量 + 'bid_p': float(data['BidPrice1']), # 买价 + 'bid_v': int(data['BidVolume1']), # 买量 + 'ask_p': float(data['AskPrice1']), # 卖价 + 'ask_v': int(data['AskVolume1']), # 卖量 + 'UpperLimitPrice': float(data['UpperLimitPrice']), # 涨停价 + 'LowerLimitPrice': float(data['LowerLimitPrice']), # 跌停价 + 'TradingDay': data['TradingDay'].decode(), # 交易日日期 + 'cum_volume': int(data['Volume']), # 最新总成交量 + 'cum_amount': float(data['Turnover']), # 最新总成交额 + 'cum_position': int(data['OpenInterest']), # 合约持仓量 + } + # 更新上一个Tick的成交量 + previous_volume[instrument_id] = int(data['Volume']) + if tick['last_volume']>0: + #print(tick['created_at'],'vol:',tick['last_volume']) + # 处理Tick数据 + on_tick(tick) + + +def can_time(hour, minute): + hour = str(hour) + minute = str(minute) + if len(minute) == 1: + minute = "0" + minute + return int(hour + minute) + +def on_tick(tick): + + tm=can_time(tick['created_at'].hour,tick['created_at'].minute) + #print(tick['symbol']) + #print(1) + #if tm>1500 and tm<2100 : + # return + if tick['last_volume']==0: + return + quotes = tick + timetick=str(tick['created_at']).replace('+08:00', '') + tsymbol=tick['symbol'] + if tsymbol not in tsymbollist.keys(): + # 获取tick的买卖价和买卖量 + #zzg_quant + tsymbollist[tsymbol]=tick + bid_p=quotes['bid_p'] + ask_p=quotes['ask_p'] + bid_v=quotes['bid_v'] + ask_v=quotes['ask_v'] + else: + # 获取上一个tick的买卖价和买卖量 + rquotes =tsymbollist[tsymbol] + bid_p=rquotes['bid_p'] + ask_p=rquotes['ask_p'] + bid_v=rquotes['bid_v'] + ask_v=rquotes['ask_v'] + tsymbollist[tsymbol]=tick + tick_dt=pd.DataFrame({'datetime':timetick,'symbol':tick['symbol'],'mainsym':tick['symbol'].rstrip('0123456789').upper(),'lastprice':tick['price'], + 'vol':tick['last_volume'], + 'bid_p':bid_p,'ask_p':ask_p,'bid_v':bid_v,'ask_v':ask_v},index=[0]) + sym = tick_dt['symbol'][0] + #print(tick_dt) + + # 直接调用tickdata,不传递resample_rule参数,让其自行从全局配置获取 + tickdata(tick_dt, sym) + +#公众号:松鼠Quant +#主页:www.quant789.com +#本策略仅作学习交流使用,实盘交易盈亏投资者个人负责!!! +#版权归松鼠Quant所有,禁止转发、转卖源码违者必究。 + +def data_of(df): + global trader_df + # 将df数据合并到trader_df中 + trader_df = pd.concat([trader_df, df], ignore_index=True) + #print('trader_df: ', len(trader_df)) + #print(trader_df) + +def process(bidDict, askDict, symbol): + try: + # 尝试从quotedict中获取对应品种的报价数据 + dic = quotedict[symbol] + bidDictResult = dic['bidDictResult'] + askDictResult = dic['askDictResult'] + except: + # 如果获取失败,则初始化bidDictResult和askDictResult为空字典 + bidDictResult, askDictResult = {}, {} + + # 将所有买盘字典和卖盘字典的key合并,并按升序排序 + sList = sorted(set(list(bidDict.keys()) + list(askDict.keys()))) + + # 遍历所有的key,将相同key的值进行累加 + for s in sList: + if s in bidDict: + if s in bidDictResult: + bidDictResult[s] = int(bidDict[s]) + bidDictResult[s] + else: + bidDictResult[s] = int(bidDict[s]) + if s not in askDictResult: + askDictResult[s] = 0 + else: + if s in askDictResult: + askDictResult[s] = int(askDict[s]) + askDictResult[s] + else: + askDictResult[s] = int(askDict[s]) + if s not in bidDictResult: + bidDictResult[s] = 0 + + # 构建包含bidDictResult和askDictResult的字典,并存入quotedict中 + df = {'bidDictResult': bidDictResult, 'askDictResult': askDictResult} + quotedict[symbol] = df + + return bidDictResult, askDictResult +#公众号:松鼠Quant +#主页:www.quant789.com +#本策略仅作学习交流使用,实盘交易盈亏投资者个人负责!!! +#版权归松鼠Quant所有,禁止转发、转卖源码违者必究。 + + +def tickdata(df, symbol): + tickdata =pd.DataFrame({'datetime':df['datetime'],'symbol':df['symbol'],'lastprice':df['lastprice'], + 'volume':df['vol'],'bid_p':df['bid_p'],'bid_v':df['bid_v'],'ask_p':df['ask_p'],'ask_v':df['ask_v']}) + try: + if symbol in tickdatadict.keys(): + rdf=tickdatadict[symbol] + rdftm=pd.to_datetime(rdf['bartime'][0]).strftime('%Y-%m-%d %H:%M:%S') + now=str(tickdata['datetime'][0]) + if now>rdftm: + try: + oo=ofdatadict[symbol] + data_of(oo) + #print('oo',oo) + if symbol in quotedict.keys(): + quotedict.pop(symbol) + if symbol in tickdatadict.keys(): + tickdatadict.pop(symbol) + if symbol in ofdatadict.keys(): + ofdatadict.pop(symbol) + except IOError as e: + print('rdftm捕获到异常',e) + tickdata['bartime'] = pd.to_datetime(tickdata['datetime']) + tickdata['open'] = tickdata['lastprice'] + tickdata['high'] = tickdata['lastprice'] + tickdata['low'] = tickdata['lastprice'] + tickdata['close'] = tickdata['lastprice'] + tickdata['starttime'] = tickdata['datetime'] + else: + tickdata['bartime'] = rdf['bartime'] + tickdata['open'] = rdf['open'] + tickdata['high'] = max(tickdata['lastprice'].values,rdf['high'].values) + tickdata['low'] = min(tickdata['lastprice'].values,rdf['low'].values) + tickdata['close'] = tickdata['lastprice'] + tickdata['volume']=df['vol']+rdf['volume'].values + tickdata['starttime'] = rdf['starttime'] + else : + print('新bar的第一个tick进入') + tickdata['bartime'] = pd.to_datetime(tickdata['datetime']) + tickdata['open'] = tickdata['lastprice'] + tickdata['high'] = tickdata['lastprice'] + tickdata['low'] = tickdata['lastprice'] + tickdata['close'] = tickdata['lastprice'] + tickdata['starttime'] = tickdata['datetime'] + except IOError as e: + print('捕获到异常',e) + + + tickdata['bartime'] = pd.to_datetime(tickdata['bartime']) + # 直接从全局配置获取resample_rule + resample_rule = GLOBAL_LLM_CONFIG.get('bar_resample_rule') + + # 使用resample_rule生成K线 + bardata = tickdata.resample(on = 'bartime', rule = resample_rule, label = 'right', closed = 'right').agg({'starttime':'first','symbol':'last','open':'first','high':'max','low':'min','close':'last','volume':'sum'}).reset_index(drop = False) + bardata =bardata.dropna().reset_index(drop = True) + bardata['bartime'] = pd.to_datetime(bardata['bartime'][0]).strftime('%Y-%m-%d %H:%M:%S') + tickdatadict[symbol]=bardata + tickdata['volume']=df['vol'].values + #print(bardata['symbol'].values,bardata['bartime'].values) + orderflow_df_new(tickdata,bardata,symbol) + # time.sleep(0.5) + +#公众号:松鼠Quant +#主页:www.quant789.com +#本策略仅作学习交流使用,实盘交易盈亏投资者个人负责!!! +#版权归松鼠Quant所有,禁止转发、转卖源码违者必究。 + +def orderflow_df_new(df_tick,df_min,symbol): + startArray = pd.to_datetime(df_min['starttime']).values + voluememin= df_min['volume'].values + highs=df_min['high'].values + lows=df_min['low'].values + opens=df_min['open'].values + closes=df_min['close'].values + #endArray = pd.to_datetime(df_min['bartime']).values + endArray = df_min['bartime'].values + #print(endArray) + deltaArray = np.zeros((len(endArray),)) + tTickArray = pd.to_datetime(df_tick['datetime']).values + bp1TickArray = df_tick['bid_p'].values + ap1TickArray = df_tick['ask_p'].values + lastTickArray = df_tick['lastprice'].values + volumeTickArray = df_tick['volume'].values + symbolarray = df_tick['symbol'].values + indexFinal = 0 + for index,tEnd in enumerate(endArray): + dt=endArray[index] + start = startArray[index] + bidDict = {} + askDict = {} + bar_vol=voluememin[index] + bar_close=closes[index] + bar_open=opens[index] + bar_low=lows[index] + bar_high=highs[index] + bar_symbol=symbolarray[index] + # for indexTick in range(indexFinal,len(df_tick)): + # if tTickArray[indexTick] >= tEnd: + # break + # elif (tTickArray[indexTick] >= start) & (tTickArray[indexTick] < tEnd): + Bp = round(bp1TickArray[0],4) + Ap = round(ap1TickArray[0],4) + LastPrice = round(lastTickArray[0],4) + Volume = volumeTickArray[0] + if LastPrice >= Ap: + if str(LastPrice) in askDict.keys(): + askDict[str(LastPrice)] += Volume + else: + askDict[str(LastPrice)] = Volume + if LastPrice <= Bp: + if str(LastPrice) in bidDict.keys(): + bidDict[str(LastPrice)] += Volume + else: + bidDict[str(LastPrice)] = Volume + # indexFinal = indexTick + bidDictResult,askDictResult = process(bidDict,askDict,symbol) + bidDictResult=dict(sorted(bidDictResult.items(),key=operator.itemgetter(0))) + askDictResult=dict(sorted(askDictResult.items(),key=operator.itemgetter(0))) + prinslist=list(bidDictResult.keys()) + asklist=list(askDictResult.values()) + bidlist=list(bidDictResult.values()) + delta=(sum(askDictResult.values()) - sum(bidDictResult.values())) + #print(prinslist,asklist,bidlist) + #print(len(prinslist),len(bidDictResult),len(askDictResult)) + df=pd.DataFrame({'price':pd.Series([prinslist]),'Ask':pd.Series([asklist]),'Bid':pd.Series([bidlist])}) + #df=pd.DataFrame({'price':pd.Series(bidDictResult.keys()),'Ask':pd.Series(askDictResult.values()),'Bid':pd.Series(bidDictResult.values())}) + df['symbol']=bar_symbol + df['datetime']=dt + df['delta']=str(delta) + df['close']=bar_close + df['open']=bar_open + df['high']=bar_high + df['low']=bar_low + df['volume']=bar_vol + #df['ticktime']=tTickArray[0] + df['dj'] = GetOrderFlow_dj(df) + ofdatadict[symbol]=df + +#公众号:松鼠Quant +#主页:www.quant789.com +#本策略仅作学习交流使用,实盘交易盈亏投资者个人负责!!! +#版权归松鼠Quant所有,禁止转发、转卖源码违者必究。 + +def GetOrderFlow_dj(kData): + Config = { + 'Value1': 3, + 'Value2': 3, + 'Value3': 3, + 'Value4': True, + } + aryData = kData + djcout = 0 + + # 遍历kData中的每一行,计算djcout指标 + for index, row in aryData.iterrows(): + kItem = aryData.iloc[index] + high = kItem['high'] + low = kItem['low'] + close = kItem['close'] + open = kItem['open'] + dtime = kItem['datetime'] + price_s = kItem['price'] + Ask_s = kItem['Ask'] + Bid_s = kItem['Bid'] + delta = kItem['delta'] + + price_s = price_s + Ask_s = Ask_s + Bid_s = Bid_s + + gj = 0 + xq = 0 + gxx = 0 + xxx = 0 + + # 遍历price_s中的每一个元素,计算相关指标 + for i in np.arange(0, len(price_s), 1): + duiji = { + 'price': 0, + 'time': 0, + 'longshort': 0, + } + + if i == 0: + delta = delta + + order= { + "Price":price_s[i], + "Bid":{ "Value":Bid_s[i]}, + "Ask":{ "Value":Ask_s[i]} + } + #空头堆积 + if i >= 0 and i < len(price_s) - 1: + if (order["Bid"]["Value"] > Ask_s[i + 1] * int(Config['Value1'])): + gxx += 1 + gj += 1 + if gj >= int(Config['Value2']) and Config['Value4'] == True: + duiji['price'] = price_s[i] + duiji['time'] = dtime + duiji['longshort'] = -1 + if float(duiji['price']) > 0: + djcout += -1 + else: + gj = 0 + #多头堆积 + if i >= 1 and i <= len(price_s) - 1: + if (order["Ask"]["Value"] > Bid_s[i - 1] * int(Config['Value1'])): + xq += 1 + xxx += 1 + if xq >= int(Config['Value2']) and Config['Value4'] == True: + duiji['price'] = price_s[i] + duiji['time'] = dtime + duiji['longshort'] = 1 + if float(duiji['price']) > 0: + djcout += 1 + else: + xq = 0 + + # 返回计算得到的djcout值 + return djcout + +#交易程序--------------------------------------------------------------------------------------------------------------------------------------------------------------------- + +class MyTrader(TraderApiBase): + def __init__(self, broker_id, td_server, investor_id, password, app_id, auth_code, md_queue=None, page_dir='', private_resume_type=2, public_resume_type=2): + # Cython类不使用super().__init__()方式调用父类初始化方法 + # TraderApiBase.__init__会由Cython自动处理 + + self.py=30 #设置委托价格的偏移,更加容易促成成交。仅螺纹,其他品种根据最小点波动,自己设置 + self.cont_df=0 + self.trailing_stop_percent = 0 #跟踪出场参数 + self.fixed_stop_loss_percent = 0 #固定出场参数 + self.dj_X=1 #开仓的堆积参数 + + self.pos=0 + self.Lots=1 #下单手数 + self.short_trailing_stop_price = 0 + self.long_trailing_stop_price = 0 + self.sl_long_price=0 + self.sl_shor_price=0 + self.out_long=0 + self.out_short=0 + self.clearing_executed=False + self.day_closed = False # 添加日内平仓标志 + self.kgdata = True #历史数据加载一次 + self.holddata=True #持仓数据加载一次 + self.use_ai_model = True # 是否使用AI模型来分析 + self.data_saved_1 = False + self.data_saved_2 = False + self.symbols='' + # 新增止盈止损字典,按合约ID索引 + self.stop_order_dict = {} + + # 新增历史数据加载相关参数 + self.load_history = False # 是否加载历史数据 + self.history_rows = 30 # 默认加载30行历史数据 + self.trader_rows = 10 # 当tader_df里的数据大于10行时开始计算指标及触发AI模型 + + # 创建并启动保存数据的线程 + self.save_data_thread = threading.Thread(target=self.run_save_last_bar_data) + self.save_data_thread.daemon = True # 设置为守护线程,主程序退出时自动结束 + self.save_data_thread.start() + + def run_save_last_bar_data(self): + """ + 在子线程中定期调用save_last_bar_data方法 + """ + while True: + try: + # 调用保存数据的方法 + self.save_last_bar_data() + # 每50秒检查一次 + time.sleep(50) + except Exception as e: + print(f"保存数据线程出现异常: {e}") + import traceback + traceback.print_exc() + # 异常后暂停一会再继续 + time.sleep(30) + + def load_history_data(self, instrument_id): + """ + 加载历史数据 + + Args: + instrument_id: 合约ID + """ + if not self.load_history: + return + + try: + # 不再只提取英文字母,使用完整的合约代码 + symbol = str(instrument_id) + json_file_path = f"traderdata/{symbol}_ofdata.json" + + # 检查traderdata目录是否存在 + if not os.path.exists("traderdata"): + print(f"traderdata目录不存在,创建目录") + os.makedirs("traderdata") + + if os.path.exists(json_file_path): + try: + # 读取JSON文件,使用lines=True确保正确读取每行JSON + df = pd.read_json(json_file_path, lines=True) + + if len(df) == 0: + print(f"历史数据文件为空: {json_file_path}") + print("将使用实时数据开始交易") + return False + + # 如果数据行数超过设定的历史行数,只取最后N行 + if len(df) > self.history_rows: + df = df.tail(self.history_rows) + print(f"历史数据超过设定行数,仅加载最后{self.history_rows}行") + + # 更新全局trader_df + global trader_df + trader_df = df + + print(f"\n===== 历史数据加载成功 =====") + print(f"合约: {instrument_id}") + print(f"数据行数: {len(df)}行") + print(f"数据时间范围: {df['datetime'].iloc[0]} 到 {df['datetime'].iloc[-1]}") + print(f"最新价格: {df['close'].iloc[-1]}") + print(f"最新成交量: {df['volume'].iloc[-1]}") + print("===========================\n") + + # 更新cont_df + self.cont_df = len(df) + + # 计算日均线 + if len(df) > 0: + df['dayma'] = df['close'].mean() + + # 计算累积的delta值 + df['delta'] = df['delta'].astype(float) + df['delta累计'] = df['delta'].cumsum() + + return True + except Exception as e: + print(f"\n===== 历史数据加载错误 =====") + print(f"合约: {instrument_id}") + print(f"读取JSON错误: {e}") + print("将使用实时数据开始交易") + print("===========================\n") + return False + else: + print(f"\n===== 历史数据加载提示 =====") + print(f"合约: {instrument_id}") + print(f"未找到历史数据文件: {json_file_path}") + print("将使用实时数据开始交易") + print("===========================\n") + return False + + except Exception as e: + print(f"\n===== 历史数据加载错误 =====") + print(f"合约: {instrument_id}") + print(f"错误信息: {e}") + print("将使用实时数据开始交易") + print("===========================\n") + return False + + #读取保存的数据 + def read_to_csv(self,symbol): + # 文件夹路径和文件路径 + # 使用完整的合约代码 + symbol = str(symbol) + folder_path = "traderdata" + file_path = os.path.join(folder_path, f"{symbol}traderdata.csv") + # 如果文件夹不存在则创建 + if not os.path.exists(folder_path): + os.makedirs(folder_path, exist_ok=True) + + # 读取保留的模型数据CSV文件 + if os.path.exists(file_path): + try: + # 检查文件是否为空 + if os.path.getsize(file_path) == 0: + print(f"CSV文件为空: {file_path}") + return + + df = pd.read_csv(file_path) + if not df.empty and self.holddata==True: + # 选择最后一行数据 + row = df.iloc[-1] + # 根据CSV文件的列名将数据赋值给相应的属性 + self.pos = int(row['pos']) + self.short_trailing_stop_price = float(row['short_trailing_stop_price']) + self.long_trailing_stop_price = float(row['long_trailing_stop_price']) + self.sl_long_price = float(row['sl_long_price']) + self.sl_shor_price = float(row['sl_shor_price']) + # self.out_long = int(row['out_long']) + # self.out_short = int(row['out_short']) + print("找到历史交易数据文件,已经更新持仓,止损止盈数据", df.iloc[-1]) + self.holddata=False + except pd.errors.EmptyDataError: + print(f"CSV文件格式错误或为空: {file_path}") + except Exception as e: + print(f"读取CSV文件时出错: {e}") + else: + pass + #print("没有找到历史交易数据文件", file_path) + #如果没有找到CSV,则初始化变量 + + pass + + #保存数据 + def save_to_csv(self,symbol): + # 使用完整的合约代码 + symbol = str(symbol) + # 创建DataFrame + data = { + 'datetime': [datetime.now().strftime('%Y-%m-%d %H:%M:%S')], # 使用当前时间 + 'pos': [self.pos], + 'short_trailing_stop_price': [self.short_trailing_stop_price], + 'long_trailing_stop_price': [self.long_trailing_stop_price], + 'sl_long_price': [self.sl_long_price], + 'sl_shor_price': [self.sl_shor_price], + } + + df = pd.DataFrame(data) + + # 确保目录存在 + folder_path = "traderdata" + if not os.path.exists(folder_path): + os.makedirs(folder_path, exist_ok=True) + + file_path = os.path.join(folder_path, f"{symbol}traderdata.csv") + + try: + # 将DataFrame保存到CSV文件 + df.to_csv(file_path, index=False) + print(f"持仓数据已保存到: {file_path}") + except Exception as e: + print(f"保存CSV文件时出错: {e}") + + + def save_last_bar_data(self): + # 获取当前时间 + current_time = datetime.now().time() + + # 第一时间范围 + clearing_time1_start = s_time(14,55) + clearing_time1_end = s_time(15,00) + # 计算clearing_time1_end加5分钟 + clearing_time1_end_plus5 = (datetime.combine(datetime.today(), clearing_time1_end) + timedelta(minutes=5)).time() + + # 第二时间范围 + clearing_time2_start = s_time(2,25) + clearing_time2_end = s_time(2,30) + # 计算clearing_time2_end加5分钟 + clearing_time2_end_plus5 = (datetime.combine(datetime.today(), clearing_time2_end) + timedelta(minutes=5)).time() + + instrument_id = self.symbols + json_file_path = f"traderdata/{instrument_id}_ofdata.json" + + # 检查是否已经有对应收盘时间的数据 + has_closing_data = False + if os.path.exists(json_file_path): + try: + # 读取现有JSON文件 + existing_df = pd.read_json(json_file_path, lines=True) + if not existing_df.empty: + # 获取最后一行数据的datetime + last_datetime = existing_df.iloc[-1]['datetime'] + + # 如果是Timestamp类型,直接获取time() + if isinstance(last_datetime, pd.Timestamp): + last_time = last_datetime.time() + # 如果是字符串类型,先转换为datetime + else: + last_datetime = pd.to_datetime(str(last_datetime)) + last_time = last_datetime.time() + + # 检查是否已经有了收盘时间的数据 + if (last_time == clearing_time1_end): + print(f"已有15:00收盘数据: {last_datetime}, 无需追加") + self.data_saved_1 = True + has_closing_data = True + elif (last_time == clearing_time2_end): + print(f"已有2:30收盘数据: {last_datetime}, 无需追加") + self.data_saved_2 = True + has_closing_data = True + except Exception as e: + print(f"读取JSON文件检查收盘数据时出错: {e}") + import traceback + traceback.print_exc() + + # 保存最后一个bar的数据到JSON文件(当时间在第一个时间段结束后的5分钟内) + if current_time >= clearing_time1_end and current_time < clearing_time1_end_plus5 and not self.data_saved_1 and not has_closing_data: + if len(trader_df) > 0: + print("第一时间段结束,保存最后一个完整bar数据到行情JSON") + + # 确保目录存在 + if not os.path.exists("traderdata"): + os.makedirs("traderdata", exist_ok=True) + + # 确保待保存的新数据中datetime字段是格式化的日期时间字符串 + if 'datetime' in trader_df.columns: + trader_df['datetime'] = trader_df['datetime'].astype(str) + + # 只获取最后一个bar的数据 + last_bar = trader_df.tail(1) + + if os.path.exists(json_file_path): + try: + # 读取现有数据 + existing_df = pd.read_json(json_file_path, lines=True) + + # 确保现有数据中的datetime字段是字符串类型 + if 'datetime' in existing_df.columns: + existing_df['datetime'] = existing_df['datetime'].astype(str) + + # 合并新数据 + combined_df = pd.concat([existing_df, last_bar], ignore_index=True) + # 保存合并后的数据,使用lines=True确保每行是独立的JSON对象 + combined_df.to_json(json_file_path, orient='records', force_ascii=False, lines=True) + print(f"最后一个bar数据已保存到行情JSON: {json_file_path}") + except Exception as e: + print(f"读取或保存JSON文件时出错: {e}") + # 如果读取出错,直接保存当前数据 + last_bar.to_json(json_file_path, orient='records', force_ascii=False, lines=True) + else: + # 创建新文件并保存最后一个bar数据 + last_bar.to_json(json_file_path, orient='records', force_ascii=False, lines=True) + print(f"创建新的行情JSON并保存最后一个bar: {json_file_path}") + + self.data_saved_1 = True # 设置标志,防止重复保存 + + # 保存最后一个bar的数据到JSON文件(当时间在第二个时间段结束后的5分钟内) + if current_time >= clearing_time2_end and current_time < clearing_time2_end_plus5 and not self.data_saved_2 and not has_closing_data: + if len(trader_df) > 0: + print("第二时间段结束,保存最后一个完整bar数据到行情JSON") + + # 确保目录存在 + if not os.path.exists("traderdata"): + os.makedirs("traderdata", exist_ok=True) + + # 确保待保存的新数据中datetime字段是格式化的日期时间字符串 + if 'datetime' in trader_df.columns: + trader_df['datetime'] = trader_df['datetime'].astype(str) + + # 只获取最后一个bar的数据 + last_bar = trader_df.tail(1) + + if os.path.exists(json_file_path): + try: + # 读取现有数据 + existing_df = pd.read_json(json_file_path, lines=True) + + # 确保现有数据中的datetime字段是字符串类型 + if 'datetime' in existing_df.columns: + existing_df['datetime'] = existing_df['datetime'].astype(str) + + # 合并新数据 + combined_df = pd.concat([existing_df, last_bar], ignore_index=True) + # 保存合并后的数据,使用lines=True确保每行是独立的JSON对象 + combined_df.to_json(json_file_path, orient='records', force_ascii=False, lines=True) + print(f"最后一个bar数据已保存到行情JSON: {json_file_path}") + except Exception as e: + print(f"读取或保存JSON文件时出错: {e}") + # 如果读取出错,直接保存当前数据 + last_bar.to_json(json_file_path, orient='records', force_ascii=False, lines=True) + else: + # 创建新文件并保存最后一个bar数据 + last_bar.to_json(json_file_path, orient='records', force_ascii=False, lines=True) + print(f"创建新的行情JSON并保存最后一个bar: {json_file_path}") + + self.data_saved_2 = True # 设置标志,防止重复保存 + + + + #每日收盘重置数据 + def day_data_reset(self,data): + # 获取当前时间 + current_time = datetime.now().time() + + # 第一时间范围 + clearing_time1_start = s_time(14,55) + clearing_time1_end = s_time(15,00) + # 第二时间范围 + clearing_time2_start = s_time(2,25) + clearing_time2_end = s_time(2,30) + current_bid = float(data['BidPrice1']) # 当前买价 + current_ask = float(data['AskPrice1']) # 当前卖价 + + + self.clearing_executed = False + # 检查当前时间第一个操作的时间范围内 + if clearing_time1_start <= current_time < clearing_time1_end and not self.clearing_executed: + self.clearing_executed = True # 设置标志变量为已执行 + self.day_closed = True # 设置日内平仓标志 + # 如果有持仓,强制平仓 + if self.pos != 0: + print("交易日结束,开始强制平仓") + # 遍历所有合约发送平仓指令 + for instrument_id in list(self.stop_order_dict.keys()): + stops = self.stop_order_dict[instrument_id] + + # 平多仓 + if stops['long']['position'] > 0: + print(f"发送平多仓指令: {instrument_id}, 手数: {stops['long']['position']}, 价格: {current_bid}") + self.insert_order(data['ExchangeID'], data['InstrumentID'], + current_bid - self.py, + stops['long']['position'], + b'1', b'3') + # 平空仓 + if stops['short']['position'] > 0: + print(f"发送平空仓指令: {instrument_id}, 手数: {stops['short']['position']}, 价格: {current_ask}") + self.insert_order(data['ExchangeID'], data['InstrumentID'], + current_ask + self.py, + stops['short']['position'], + b'0', b'3') + + # 清空所有合约的持仓信息 + for instrument_id in list(self.stop_order_dict.keys()): + self.clear_position_info(instrument_id, 'all') + + print("日内交易已结束,禁止开新仓") + + # 检查当前时间是否在第二个操作的时间范围内 + elif clearing_time2_start <= current_time < clearing_time2_end and not self.clearing_executed: + self.clearing_executed = True # 设置标志变量为已执行 + self.day_closed = True # 设置日内平仓标志 + # 如果有持仓,强制平仓 + if self.pos != 0: + print("交易日结束,开始强制平仓") + # 遍历所有合约发送平仓指令 + for instrument_id in list(self.stop_order_dict.keys()): + stops = self.stop_order_dict[instrument_id] + + # 平多仓 + if stops['long']['position'] > 0: + print(f"发送平多仓指令: {instrument_id}, 手数: {stops['long']['position']}, 价格: {current_bid}") + self.insert_order(data['ExchangeID'], data['InstrumentID'], + current_bid - self.py, + stops['long']['position'], + b'1', b'3') + # 平空仓 + if stops['short']['position'] > 0: + print(f"发送平空仓指令: {instrument_id}, 手数: {stops['short']['position']}, 价格: {current_ask}") + self.insert_order(data['ExchangeID'], data['InstrumentID'], + current_ask + self.py, + stops['short']['position'], + b'0', b'3') + # 清空所有合约的持仓信息 + for instrument_id in list(self.stop_order_dict.keys()): + self.clear_position_info(instrument_id, 'all') + + print("日内交易已结束,禁止开新仓") + else: + self.clearing_executed = False + self.day_closed = False + return self.clearing_executed + + def OnRtnTrade(self, pTrade): + print("||成交回报||", pTrade) + + # 获取成交信息 + instrument_id = pTrade['InstrumentID'].decode() + direction = pTrade['Direction'].decode() # '0'为买入,'1'为卖出 + offset_flag = pTrade['OffsetFlag'].decode() # '0'为开仓,'1'为平仓,'3'为平今 + volume = pTrade['Volume'] + price = pTrade['Price'] + + # 根据成交类型更新持仓信息 + if offset_flag in ['1', '3']: # 平仓或平今 + # 判断平的是多头还是空头 + if direction == '1': # 卖出,平多头 + print(f"平多头成交: {instrument_id}, 价格: {price}, 数量: {volume}") + # 清空多头持仓信息 + self.clear_position_info(instrument_id, 'long') + else: # 买入,平空头 + print(f"平空头成交: {instrument_id}, 价格: {price}, 数量: {volume}") + # 清空空头持仓信息 + self.clear_position_info(instrument_id, 'short') + + elif offset_flag == '0': # 开仓 + if direction == '0': # 买入,开多头 + print(f"开多头成交: {instrument_id}, 价格: {price}, 数量: {volume}") + # 如果有空头持仓,先清空 + if instrument_id in self.stop_order_dict and self.stop_order_dict[instrument_id]['short']['position'] > 0: + self.clear_position_info(instrument_id, 'short') + + # # 设置多头持仓信息 + # sl_price = price * (1 - self.fixed_stop_loss_percent) # 默认止损价 + # tp_price = price * (1 + self.trailing_stop_percent) # 默认止盈价 + + # # 设置初始跟踪止损价,与开仓价保持一定距离 + # initial_trailing_stop = price * (1 - self.trailing_stop_percent) + + # log_message = f"设置止损价: {sl_price}, 止盈价: {tp_price}, 跟踪止损价: {initial_trailing_stop}, 跟踪百分比: {self.trailing_stop_percent*100:.3f}%" + # STOPLOSS_LOGGER.info(log_message) + + # # 更新多头持仓信息,设置合理的跟踪止损初始值 + # self.update_stop_order_dict(instrument_id, 'long', volume, price, sl_price, tp_price, initial_trailing_stop) + # self.pos = volume # 更新全局持仓状态 + + # # 兼容旧代码 + # self.long_trailing_stop_price = initial_trailing_stop + # self.sl_long_price = sl_price + # self.save_to_csv(instrument_id) + + else: # 卖出,开空头 + print(f"开空头成交: {instrument_id}, 价格: {price}, 数量: {volume}") + # 如果有多头持仓,先清空 + if instrument_id in self.stop_order_dict and self.stop_order_dict[instrument_id]['long']['position'] > 0: + self.clear_position_info(instrument_id, 'long') + + # # 设置空头持仓信息 + # sl_price = price * (1 + self.fixed_stop_loss_percent) # 默认止损价 + # tp_price = price * (1 - self.trailing_stop_percent) # 默认止盈价 + + # # 设置初始跟踪止损价,与开仓价保持一定距离 + # initial_trailing_stop = price * (1 + self.trailing_stop_percent) + + # log_message = f"设置止损价: {sl_price}, 止盈价: {tp_price}, 跟踪止损价: {initial_trailing_stop}, 跟踪百分比: {self.trailing_stop_percent*100:.3f}%" + # STOPLOSS_LOGGER.info(log_message) + + # # 更新空头持仓信息,设置合理的跟踪止损初始值 + # self.update_stop_order_dict(instrument_id, 'short', self.Lots, price, sl_price, tp_price, initial_trailing_stop) + # self.pos = -1 # 更新全局持仓状态 + + # # 兼容旧代码 + # self.short_trailing_stop_price = initial_trailing_stop + # self.sl_shor_price = sl_price + # self.save_to_csv(instrument_id) + + def OnRspOrderInsert(self, pInputOrder, pRspInfo, nRequestID, bIsLast): + print("||OnRspOrderInsert||", pInputOrder, pRspInfo, nRequestID, bIsLast) + + #公众号:松鼠Quant + #主页:www.quant789.com + #本策略仅作学习交流使用,实盘交易盈亏投资者个人负责!!! + #版权归松鼠Quant所有,禁止转发、转卖源码违者必究。 + + #注意:运行前请先安装好algoplus, + # pip install AlgoPlus + #http://www.algo.plus/ctp/python/0103001.html + + # 订单状态通知 + def OnRtnOrder(self, pOrder): + print("||订单回报||", pOrder) + + def Join(self): + data = None + # 记录上次加载止盈止损信息的时间和合约 + last_load_time = {} + + while True: + if self.status == 0 and not self.md_queue.empty(): + + while not self.md_queue.empty(): + data = self.md_queue.get(block=False) + instrument_id = data['InstrumentID'].decode() # 品种代码 + self.symbols=instrument_id + # 首次运行时加载历史数据 + if self.kgdata: + self.load_history_data(instrument_id) + self.kgdata = False + + # 加载该合约的止盈止损信息,避免频繁加载 + current_time = time.time() + if instrument_id not in last_load_time or current_time - last_load_time.get(instrument_id, 0) > 60: # 每60秒才重新加载一次 + self.load_stop_orders_from_file(instrument_id) + last_load_time[instrument_id] = current_time + + # 检查止盈止损条件 + self.check_stop_conditions(data) + + # 在每个tick都检查和处理AI交易信号 - 移到这里以提高执行速度 + if self.use_ai_model: + self.check_and_process_ai_signals(data) + + # 原有代码... + self.read_to_csv(instrument_id) + self.day_data_reset(data) + tickcome(data) + #新K线开始,启动交易程序 and 保存行情数据 + if len(trader_df)>self.cont_df and len(trader_df)>0: + # 计算日均线 + trader_df['dayma'] = trader_df['close'].mean() + + # 计算累积的delta值 + trader_df['delta'] = trader_df['delta'].astype(float) + trader_df['delta累计'] = trader_df['delta'].cumsum() + + # 检查文件是否存在 + json_file_path = f"traderdata/{instrument_id}_ofdata.json" + + # 确保待保存的新数据中datetime字段是格式化的日期时间字符串 + if 'datetime' in trader_df.columns: + # 无论什么类型,都统一转换为字符串格式 + trader_df['datetime'] = trader_df['datetime'].astype(str) + + if os.path.exists(json_file_path): + try: + # 读取现有数据 + existing_df = pd.read_json(json_file_path, lines=True) + + # 确保现有数据中的datetime字段是字符串类型 + if 'datetime' in existing_df.columns: + existing_df['datetime'] = existing_df['datetime'].astype(str) + + # 合并新数据 + combined_df = pd.concat([existing_df, trader_df.tail(1)], ignore_index=True) + # 保存合并后的数据,使用lines=True确保每行是独立的JSON对象 + combined_df.to_json(json_file_path, orient='records', force_ascii=False, lines=True) + except Exception as e: + print(f"读取或保存JSON文件时出错: {e}") + # 如果读取出错,直接保存当前数据 + trader_df.to_json(json_file_path, orient='records', force_ascii=False, lines=True) + else: + # 创建新文件并保存整个DataFrame + trader_df.to_json(json_file_path, orient='records', force_ascii=False, lines=True) + + # 更新跟踪止损价格 - 兼容旧版本代码 + if self.long_trailing_stop_price >0 and self.pos>0: + self.long_trailing_stop_price = trader_df['low'].iloc[-1] if self.long_trailing_stop_price0 and self.pos<0: + self.short_trailing_stop_price = trader_df['high'].iloc[-1] if trader_df['high'].iloc[-1] self.trader_rows: + AI_THREAD_RUNNING = True + ai_thread = threading.Thread( + target=self.background_model_call, + args=(trader_df, instrument_id) + ) + ai_thread.daemon = True # 设置为守护线程,主程序退出时自动结束 + ai_thread.start() + print("启动AI分析线程...") + + print(trader_df['datetime']) + self.cont_df=len(trader_df) + else: + time.sleep(0.5) + + def background_model_call(self, data_df, instrument_id): + """ + 在后台线程中调用大模型,并将交易信号放入队列 + + Args: + data_df: 包含订单流数据的DataFrame + instrument_id: 合约ID + """ + global AI_THREAD_RUNNING + + start_time = datetime.now() + log_message = f"\n===== 开始AI分析 [{start_time.strftime('%Y-%m-%d %H:%M:%S')}] =====" + print(log_message) + AI_LOGGER.info(log_message) + + log_message = f"正在分析合约: {instrument_id}" + print(log_message) + AI_LOGGER.info(log_message) + + try: + # 复制DataFrame以避免在不同线程间共享数据可能导致的问题 + df_copy = data_df.copy() + + # 输出分析的数据行数 + log_message = f"分析数据行数: {len(df_copy)}" + print(log_message) + AI_LOGGER.info(log_message) + + log_message = f"最新价格: {df_copy['close'].iloc[-1] if len(df_copy) > 0 else 'N/A'}" + print(log_message) + AI_LOGGER.info(log_message) + + # 调用大模型获取交易信号 + trading_signal = call_deepseek_model(df_copy, self) # 传递self参数 + + # 计算分析耗时 + end_time = datetime.now() + elapsed = (end_time - start_time).total_seconds() + + # 将交易信号和合约ID一起放入队列 + signal_data = { + 'signal': trading_signal, + 'instrument_id': instrument_id, + 'timestamp': end_time # 使用结束时间作为时间戳 + } + + AI_SIGNAL_QUEUE.put(signal_data) + + log_message = f"AI模型分析完成,结果已放入队列,耗时: {elapsed:.2f}秒" + print(log_message) + AI_LOGGER.info(log_message) + + log_message = f"分析结果: {trading_signal}" + print(log_message) + AI_LOGGER.info(log_message) + + log_message = "===== AI分析完成 =====" + print(log_message + "\n") + AI_LOGGER.info(log_message) + except Exception as e: + end_time = datetime.now() + elapsed = (end_time - start_time).total_seconds() + + log_message = f"AI模型分析线程出现异常: {e}" + print(log_message) + AI_LOGGER.error(log_message) + + print(f"异常详情:") + import traceback + error_traceback = traceback.format_exc() + AI_LOGGER.error(f"异常详情:\n{error_traceback}") + traceback.print_exc() + + log_message = f"分析失败,耗时: {elapsed:.2f}秒" + print(log_message) + AI_LOGGER.error(log_message) + + log_message = "===== AI分析异常结束 =====" + print(log_message + "\n") + AI_LOGGER.error(log_message) + finally: + # 标记线程已完成 + AI_THREAD_RUNNING = False + + + #公众号:松鼠Quant + #主页:www.quant789.com + #本策略仅作学习交流使用,实盘交易盈亏投资者个人负责!!! + #版权归松鼠Quant所有,禁止转发、转卖源码违者必究。 + + #注意:运行前请先安装好algoplus, + # pip install AlgoPlus + #http://www.algo.plus/ctp/python/0103001.html + + def check_and_process_ai_signals(self, data): + """检查并处理AI产生的交易信号""" + if AI_SIGNAL_QUEUE.empty(): + return + + # 从队列中获取信号 + signal_data = AI_SIGNAL_QUEUE.get() + trading_signal = signal_data['signal'] + instrument_id = signal_data['instrument_id'] + signal_time = signal_data['timestamp'] + + # 验证合约ID是否匹配,不匹配则放回队列 + if instrument_id != data['InstrumentID'].decode(): + AI_SIGNAL_QUEUE.put(signal_data) + return + + # 提取交易信号数据 + action = trading_signal.get('action', '不操作') + confidence = trading_signal.get('confidence', 0) + reason = trading_signal.get('reason', '') + stop_loss = trading_signal.get('stop_loss', 0) + take_profit = trading_signal.get('take_profit', 0) + trailing_percent = trading_signal.get('trailing_percent', 0) + + # 记录日志 + log_lines = [ + f"\n===== 执行AI模型交易信号 [{datetime.now().strftime('%Y-%m-%d %H:%M:%S')}] =====", + f"信号生成时间: {signal_time.strftime('%Y-%m-%d %H:%M:%S')}", + f"信号类型: {action}", + #f"置信度: {confidence}", + f"理由: {reason}" + ] + for line in log_lines: + print(line) + SIGNAL_LOGGER.info(line) + + # 确保合约在止损止盈字典中 + self._ensure_stop_order_dict(instrument_id) + current_stops = self.stop_order_dict[instrument_id] + + # 处理跟踪止损百分比更新 + self._update_trailing_stop_percent(trailing_percent, instrument_id, data) + + # # 只有当置信度大于等于6时才执行交易(已经弃用,不再根据置信度执行交易) + # if confidence < 6: + # print(f"信号置信度{confidence}低于执行阈值(6),不执行交易") + # print("===== 交易信号处理完成 =====\n") + # return + + print(f"开始执行交易,当前价格: 买一{data['BidPrice1']} / 卖一{data['AskPrice1']}") + + # 根据不同交易行为执行相应操作 + if action == '开多' and current_stops['long']['position'] <= 0: + self._handle_open_long(data, instrument_id, stop_loss, take_profit) + + elif action == '开空' and current_stops['short']['position'] <= 0: + self._handle_open_short(data, instrument_id, stop_loss, take_profit) + + elif action == '平多' and current_stops['long']['position'] > 0: + self._handle_close_long(data, instrument_id) + + elif action == '平空' and current_stops['short']['position'] > 0: + self._handle_close_short(data, instrument_id) + + elif action == '平多开空' and current_stops['long']['position'] > 0: + self._handle_close_long_open_short(data, instrument_id, stop_loss, take_profit) + + elif action == '平空开多' and current_stops['short']['position'] > 0: + self._handle_close_short_open_long(data, instrument_id, stop_loss, take_profit) + + elif action == '不操作': + self._handle_adjust_stop_levels(instrument_id, stop_loss, take_profit) + + print("===== 交易信号执行完成 =====\n") + + def _ensure_stop_order_dict(self, instrument_id): + """确保指定合约在止损止盈字典中存在""" + if instrument_id not in self.stop_order_dict: + self.stop_order_dict[instrument_id] = { + 'long': {'position': 0, 'entry_price': 0, 'stop_loss': 0, 'take_profit': 0, 'trailing_stop': 0}, + 'short': {'position': 0, 'entry_price': 0, 'stop_loss': 0, 'take_profit': 0, 'trailing_stop': 0} + } + + def _update_trailing_stop_percent(self, trailing_percent, instrument_id, data): + """更新跟踪止损百分比""" + if not (0.0001 <= trailing_percent <= 0.001): + return + + old_percent = self.trailing_stop_percent + self.trailing_stop_percent = trailing_percent + log_message = f"更新跟踪止损百分比参数: {old_percent*100:.3f}% -> {trailing_percent*100:.3f}%" + STOPLOSS_LOGGER.info(log_message) + + current_stops = self.stop_order_dict[instrument_id] + + # 更新多头持仓的跟踪止损价 + if current_stops['long']['position'] > 0: + new_trailing_stop = float(data['BidPrice1']) * (1 - self.trailing_stop_percent) + old_trailing_stop = current_stops['long']['trailing_stop'] + + if new_trailing_stop > old_trailing_stop: + self.update_stop_order_dict(instrument_id, 'long', None, None, None, None, new_trailing_stop) + self.long_trailing_stop_price = new_trailing_stop # 兼容旧代码 + self.save_to_csv(instrument_id) + + # 更新空头持仓的跟踪止损价 + elif current_stops['short']['position'] > 0: + new_trailing_stop = float(data['AskPrice1']) * (1 + self.trailing_stop_percent) + old_trailing_stop = current_stops['short']['trailing_stop'] + + if new_trailing_stop < old_trailing_stop or old_trailing_stop == 0: + self.update_stop_order_dict(instrument_id, 'short', None, None, None, None, new_trailing_stop) + self.short_trailing_stop_price = new_trailing_stop # 兼容旧代码 + self.save_to_csv(instrument_id) + + def _handle_open_long(self, data, instrument_id, stop_loss, take_profit): + """处理开多头仓位""" + # 如果持有空头头寸,先平空 + current_stops = self.stop_order_dict[instrument_id] + if current_stops['short']['position'] > 0: + print('执行平空操作') + self.insert_order(data['ExchangeID'], data['InstrumentID'], + data['AskPrice1']+self.py, + current_stops['short']['position'], + b'0', b'3') + self.clear_position_info(instrument_id, 'short') + + # 开多 + print('执行开多操作') + entry_price = float(data['AskPrice1']) + self.insert_order(data['ExchangeID'], data['InstrumentID'], + entry_price+self.py, self.Lots, b'0', b'0') + + # 设置止损止盈 + sl_price = stop_loss + tp_price = take_profit + initial_trailing_stop = entry_price * (1 - self.trailing_stop_percent) + + # 记录止损止盈设置 + STOPLOSS_LOGGER.info(f"设置止损价: {sl_price}, 止盈价: {tp_price}, 跟踪止损价: {initial_trailing_stop}, 跟踪百分比: {self.trailing_stop_percent*100:.3f}%") + + # 更新持仓信息 + self.update_stop_order_dict(instrument_id, 'long', self.Lots, entry_price, sl_price, tp_price, initial_trailing_stop) + self.pos = 1 # 更新全局持仓状态 + + # 兼容旧代码 + self.long_trailing_stop_price = initial_trailing_stop + self.sl_long_price = sl_price + self.save_to_csv(instrument_id) + + def _handle_open_short(self, data, instrument_id, stop_loss, take_profit): + """处理开空头仓位""" + # 如果持有多头头寸,先平多 + current_stops = self.stop_order_dict[instrument_id] + if current_stops['long']['position'] > 0: + print('执行平多操作') + self.insert_order(data['ExchangeID'], data['InstrumentID'], + data['BidPrice1']-self.py, + current_stops['long']['position'], + b'1', b'3') + self.clear_position_info(instrument_id, 'long') + + # 开空 + print('执行开空操作') + entry_price = float(data['BidPrice1']) + self.insert_order(data['ExchangeID'], data['InstrumentID'], + entry_price-self.py, self.Lots, b'1', b'0') + + # 设置止损止盈 + sl_price = stop_loss + tp_price = take_profit + initial_trailing_stop = entry_price * (1 + self.trailing_stop_percent) + + # 记录止损止盈设置 + STOPLOSS_LOGGER.info(f"设置止损价: {sl_price}, 止盈价: {tp_price}, 跟踪止损价: {initial_trailing_stop}, 跟踪百分比: {self.trailing_stop_percent*100:.3f}%") + + # 更新持仓信息 + self.update_stop_order_dict(instrument_id, 'short', self.Lots, entry_price, sl_price, tp_price, initial_trailing_stop) + self.pos = -1 # 更新全局持仓状态 + + # 兼容旧代码 + self.short_trailing_stop_price = initial_trailing_stop + self.sl_shor_price = sl_price + self.save_to_csv(instrument_id) + + def _handle_close_long(self, data, instrument_id): + """处理平多头仓位""" + current_stops = self.stop_order_dict[instrument_id] + print('执行平多操作') + self.insert_order(data['ExchangeID'], data['InstrumentID'], + data['BidPrice1']-self.py, + current_stops['long']['position'], + b'1', b'3') + self.clear_position_info(instrument_id, 'long') + + def _handle_close_short(self, data, instrument_id): + """处理平空头仓位""" + current_stops = self.stop_order_dict[instrument_id] + print('执行平空操作') + self.insert_order(data['ExchangeID'], data['InstrumentID'], + data['AskPrice1']+self.py, + current_stops['short']['position'], + b'0', b'3') + self.clear_position_info(instrument_id, 'short') + + def _handle_close_long_open_short(self, data, instrument_id, stop_loss, take_profit): + """处理平多开空操作""" + print('执行平多开空操作') + + # 第一步:平多 + self._handle_close_long(data, instrument_id) + + # 第二步:开空 + print('2. 执行开空操作') + entry_price = float(data['BidPrice1']) + self.insert_order(data['ExchangeID'], data['InstrumentID'], + entry_price-self.py, self.Lots, b'1', b'0') + + # 设置止损止盈 + sl_price = stop_loss + tp_price = take_profit + initial_trailing_stop = entry_price * (1 + self.trailing_stop_percent) + + # 记录止损止盈设置 + STOPLOSS_LOGGER.info(f"设置止损价: {sl_price}, 止盈价: {tp_price}, 跟踪止损价: {initial_trailing_stop}, 跟踪百分比: {self.trailing_stop_percent*100:.3f}%") + + # 更新持仓信息 + self.update_stop_order_dict(instrument_id, 'short', self.Lots, entry_price, sl_price, tp_price, initial_trailing_stop) + self.pos = -1 # 更新全局持仓状态 + + # 兼容旧代码 + self.short_trailing_stop_price = initial_trailing_stop + self.sl_shor_price = sl_price + self.save_to_csv(instrument_id) + + def _handle_close_short_open_long(self, data, instrument_id, stop_loss, take_profit): + """处理平空开多操作""" + print('执行平空开多操作') + + # 第一步:平空 + self._handle_close_short(data, instrument_id) + + # 第二步:开多 + print('2. 执行开多操作') + entry_price = float(data['AskPrice1']) + self.insert_order(data['ExchangeID'], data['InstrumentID'], + entry_price+self.py, self.Lots, b'0', b'0') + + # 设置止损止盈 + sl_price = stop_loss + tp_price = take_profit + initial_trailing_stop = entry_price * (1 - self.trailing_stop_percent) + + # 记录止损止盈设置 + STOPLOSS_LOGGER.info(f"设置止损价: {sl_price}, 止盈价: {tp_price}, 跟踪止损价: {initial_trailing_stop}, 跟踪百分比: {self.trailing_stop_percent*100:.3f}%") + + # 更新持仓信息 + self.update_stop_order_dict(instrument_id, 'long', self.Lots, entry_price, sl_price, tp_price, initial_trailing_stop) + self.pos = 1 # 更新全局持仓状态 + + # 兼容旧代码 + self.long_trailing_stop_price = initial_trailing_stop + self.sl_long_price = sl_price + self.save_to_csv(instrument_id) + + def _handle_adjust_stop_levels(self, instrument_id, stop_loss, take_profit): + """调整止损止盈价格""" + current_stops = self.stop_order_dict[instrument_id] + + # 调整止损价 + if stop_loss > 0: + if current_stops['long']['position'] > 0: # 多头持仓 + self.update_stop_order_dict(instrument_id, 'long', None, None, stop_loss, None, None) + print(f'已调整多头止损价: {stop_loss}') + self.sl_long_price = stop_loss # 兼容旧代码 + self.save_to_csv(instrument_id) + elif current_stops['short']['position'] > 0: # 空头持仓 + self.update_stop_order_dict(instrument_id, 'short', None, None, stop_loss, None, None) + print(f'已调整空头止损价: {stop_loss}') + self.sl_shor_price = stop_loss # 兼容旧代码 + self.save_to_csv(instrument_id) + + # 调整止盈价 + if take_profit > 0: + if current_stops['long']['position'] > 0: # 多头持仓 + self.update_stop_order_dict(instrument_id, 'long', None, None, None, take_profit, None) + print(f'已调整多头止盈价: {take_profit}') + self.save_to_csv(instrument_id) + elif current_stops['short']['position'] > 0: # 空头持仓 + self.update_stop_order_dict(instrument_id, 'short', None, None, None, take_profit, None) + print(f'已调整空头止盈价: {take_profit}') + self.save_to_csv(instrument_id) + + #公众号:松鼠Quant + #主页:www.quant789.com + #本策略仅作学习交流使用,实盘交易盈亏投资者个人负责!!! + #版权归松鼠Quant所有,禁止转发、转卖源码违者必究。 + + #注意:运行前请先安装好algoplus, + # pip install AlgoPlus + #http://www.algo.plus/ctp/python/0103001.html + + def format_data_for_llm(self, df): + """ + 将DataFrame格式化为适合LLM分析的文本格式,包含历史交易信息 + """ + # 提取最近几条记录 + recent_data = df.tail(self.trader_rows) + + # 构建基本信息 + data_text = "订单流数据分析:\n\n" + + # 提取最新行情数据 + instrument_id = recent_data['symbol'].iloc[-1] + + # 添加最新价格和交易量信息 + data_text += f"当前时间: {recent_data['datetime'].iloc[-1]}\n" + data_text += f"当前价格: {recent_data['close'].iloc[-1]}\n" + data_text += f"开盘价: {recent_data['open'].iloc[-1]}\n" + data_text += f"最高价: {recent_data['high'].iloc[-1]}\n" + data_text += f"最低价: {recent_data['low'].iloc[-1]}\n" + data_text += f"成交量: {recent_data['volume'].iloc[-1]}\n" + + # 计算价格趋势 + if len(recent_data) >= 5: + price_trend = recent_data['close'].pct_change().tail(5).mean() * 100 + data_text += f"价格短期趋势: {'上涨' if price_trend > 0 else '下跌'} ({price_trend:.2f}%)\n" + + # 计算价格波动性 + if len(recent_data) >= 5: + volatility = recent_data['close'].pct_change().tail(5).std() * 100 + data_text += f"价格波动性: {volatility:.2f}%\n" + + # 添加支撑和阻力位分析 + recent_high = recent_data['high'].max() + recent_low = recent_data['low'].min() + data_text += f"近期阻力位: {recent_high}\n" + data_text += f"近期支撑位: {recent_low}\n" + + # 添加均线分析 - 计算5、10、20均线 + if len(df) >= 20: + # 计算均线 + ma5 = df['close'].rolling(5).mean().iloc[-1] + ma10 = df['close'].rolling(10).mean().iloc[-1] + ma20 = df['close'].rolling(20).mean().iloc[-1] + + data_text += f"MA5: {ma5:.2f}\n" + data_text += f"MA10: {ma10:.2f}\n" + data_text += f"MA20: {ma20:.2f}\n" + + # 判断均线形态 + if abs(ma5 - ma10) / ma10 < 0.01 and abs(ma10 - ma20) / ma20 < 0.01: + ma_pattern = "均线粘合" + elif ma5 > ma10 and ma10 > ma20: + ma_pattern = "多头排列" + elif ma5 < ma10 and ma10 < ma20: + ma_pattern = "空头排列" + elif ma5 > ma10 and ma10 < ma20: + ma_pattern = "金叉形态" + elif ma5 < ma10 and ma10 > ma20: + ma_pattern = "死叉形态" + else: + ma_pattern = "无明显形态" + + data_text += f"均线形态: {ma_pattern}\n" + + # 价格与均线关系 + current_price = df['close'].iloc[-1] + data_text += f"价格相对MA5: {'上方' if current_price > ma5 else '下方'} ({(current_price/ma5-1)*100:.2f}%)\n" + data_text += f"价格相对MA10: {'上方' if current_price > ma10 else '下方'} ({(current_price/ma10-1)*100:.2f}%)\n" + data_text += f"价格相对MA20: {'上方' if current_price > ma20 else '下方'} ({(current_price/ma20-1)*100:.2f}%)\n" + + # 日内超涨超跌分析 + if len(df) >= 20: + # 计算日内振幅 + daily_high = df['high'].iloc[-20:].max() + daily_low = df['low'].iloc[-20:].min() + daily_range = (daily_high - daily_low) / daily_low * 100 + + # 当前价格在日内范围的位置 + current_in_range = (df['close'].iloc[-1] - daily_low) / (daily_high - daily_low) * 100 if (daily_high - daily_low) > 0 else 50 + + data_text += f"日内振幅: {daily_range:.2f}%\n" + data_text += f"价格在日内范围的位置: {current_in_range:.2f}% (0%为日低, 100%为日高)\n" + + # 判断超涨超跌 + if current_in_range > 85: + data_text += "日内状态: 可能超涨\n" + elif current_in_range < 15: + data_text += "日内状态: 可能超跌\n" + else: + data_text += "日内状态: 正常区间\n" + + # 形态识别 + if len(df) >= 20: + # 简单K线形态识别 + recent_k = df.tail(5).copy() + + # 计算实体和影线 + recent_k['body'] = abs(recent_k['close'] - recent_k['open']) + recent_k['upper_shadow'] = recent_k.apply(lambda x: x['high'] - max(x['open'], x['close']), axis=1) + recent_k['lower_shadow'] = recent_k.apply(lambda x: min(x['open'], x['close']) - x['low'], axis=1) + + # 最新K线特征 + latest_k = recent_k.iloc[-1] + prev_k = recent_k.iloc[-2] if len(recent_k) > 1 else None + + data_text += "\nK线形态分析:\n" + + # 判断最新K线类型 + if latest_k['body'] == 0: + k_type = "十字星" + elif latest_k['upper_shadow'] > 2 * latest_k['body'] and latest_k['lower_shadow'] < 0.5 * latest_k['body']: + k_type = "上影线长" + elif latest_k['lower_shadow'] > 2 * latest_k['body'] and latest_k['upper_shadow'] < 0.5 * latest_k['body']: + k_type = "下影线长" + elif latest_k['close'] > latest_k['open'] and latest_k['body'] > np.mean(recent_k['body']): + k_type = "大阳线" + elif latest_k['close'] < latest_k['open'] and latest_k['body'] > np.mean(recent_k['body']): + k_type = "大阴线" + elif latest_k['close'] > latest_k['open']: + k_type = "小阳线" + elif latest_k['close'] < latest_k['open']: + k_type = "小阴线" + else: + k_type = "普通K线" + + data_text += f"最新K线类型: {k_type}\n" + + # 判断简单组合形态 + if prev_k is not None: + if prev_k['close'] < prev_k['open'] and latest_k['close'] > latest_k['open'] and latest_k['open'] <= prev_k['close'] and latest_k['close'] > prev_k['open']: + data_text += "组合形态: 可能构成看涨吞没形态\n" + elif prev_k['close'] > prev_k['open'] and latest_k['close'] < latest_k['open'] and latest_k['open'] >= prev_k['close'] and latest_k['close'] < prev_k['open']: + data_text += "组合形态: 可能构成看跌吞没形态\n" + elif prev_k['close'] < prev_k['open'] and latest_k['close'] > latest_k['open'] and latest_k['body'] > 1.5 * prev_k['body']: + data_text += "组合形态: 可能构成看涨势能增强\n" + elif prev_k['close'] > prev_k['open'] and latest_k['close'] < latest_k['open'] and latest_k['body'] > 1.5 * prev_k['body']: + data_text += "组合形态: 可能构成看跌势能增强\n" + + # 添加订单流特定数据 + data_text += f"\n订单流净值: {recent_data['delta'].iloc[-1]}\n" + data_text += f"订单流累计值: {recent_data['delta累计'].iloc[-1] if 'delta累计' in recent_data.columns else '无数据'}\n" + data_text += f"堆积指标: {recent_data['dj'].iloc[-1]}\n" + + # 添加日均线数据 + data_text += f"日均线: {recent_data['dayma'].iloc[-1] if 'dayma' in recent_data.columns else '无数据'}\n" + + # 添加价格与日均线的关系 + if 'dayma' in recent_data.columns: + price_above_ma = recent_data['close'].iloc[-1] > recent_data['dayma'].iloc[-1] + data_text += f"价格位于日均线: {'上方' if price_above_ma else '下方'}\n" + + # 订单流全面分析 + data_text += "\n订单流详细分析:\n" + + # 计算订单流趋势 + if len(recent_data) >= 5: + delta_values = recent_data['delta'].values + delta_trend = np.mean(np.diff(delta_values)) if len(delta_values) > 1 else 0 + data_text += f"订单流趋势: {'增强中' if delta_trend > 0 else '减弱中'} (变化率: {delta_trend:.2f})\n" + + # 计算订单流强度(使用绝对值的平均值) + delta_strength = np.mean(np.abs(recent_data['delta'].values)) + data_text += f"订单流强度: {delta_strength:.2f}\n" + + # 订单流指标超涨超跌分析 + if len(df) >= 20: + delta_values = df['delta'].iloc[-20:].values + delta_mean = np.mean(delta_values) + delta_std = np.std(delta_values) + current_delta = df['delta'].iloc[-1] + + # Z分数计算 + if delta_std > 0: + delta_z = (current_delta - delta_mean) / delta_std + data_text += f"订单流偏离度(Z分数): {delta_z:.2f}\n" + + if delta_z > 2: + data_text += "订单流状态: 可能超买\n" + elif delta_z < -2: + data_text += "订单流状态: 可能超卖\n" + else: + data_text += "订单流状态: 正常区间\n" + + # 买卖力量对比 + if 'bid_v' in recent_data.columns and 'ask_v' in recent_data.columns: + bid_power = recent_data['bid_v'].mean() + ask_power = recent_data['ask_v'].mean() + power_ratio = bid_power / ask_power if ask_power != 0 else float('inf') + data_text += f"买卖比例: {power_ratio:.2f} (>1买方强势,<1卖方强势)\n" + + # 订单流累计趋势 + if 'delta累计' in recent_data.columns and len(recent_data) >= 2: + cumulative_start = recent_data['delta累计'].iloc[0] + cumulative_end = recent_data['delta累计'].iloc[-1] + cumulative_change = cumulative_end - cumulative_start + data_text += f"累计订单流变化: {cumulative_change:.2f} (从 {cumulative_start:.2f} 到 {cumulative_end:.2f})\n" + + # 订单流波动性 + delta_volatility = np.std(recent_data['delta'].values) + data_text += f"订单流波动性: {delta_volatility:.2f}\n" + + # 订单流与价格相关性 + if len(recent_data) >= 10: # 确保有足够数据计算相关性 + price_changes = recent_data['close'].pct_change().dropna() + delta_changes = recent_data['delta'].iloc[1:].reset_index(drop=True) # 对齐索引 + if len(price_changes) > 0 and len(delta_changes) == len(price_changes): + try: + correlation = np.corrcoef(price_changes, delta_changes)[0, 1] if len(price_changes) > 1 else 0 + data_text += f"订单流与价格相关性: {correlation:.2f}\n" + data_text += f"相关性解读: {'强正相关' if correlation > 0.7 else '正相关' if correlation > 0.3 else '弱相关' if correlation > -0.3 else '负相关' if correlation > -0.7 else '强负相关'}\n" + except: + data_text += "订单流与价格相关性: 计算错误\n" + + # 订单流势能分析(最近几分钟的方向) + recent_deltas = recent_data['delta'].tail(5).values + positive_count = sum(1 for x in recent_deltas if x > 0) + negative_count = sum(1 for x in recent_deltas if x < 0) + data_text += f"最近订单流方向: {'多头主导' if positive_count > negative_count else '空头主导' if positive_count < negative_count else '方向不明'} ({positive_count}正/{negative_count}负)\n" + + # 订单流强弱可视化 + delta_last_10 = recent_data['delta'].tail(10).values # 使用更多数据计算标准差 + delta_std = np.std(delta_last_10) + delta_last_5 = recent_data['delta'].tail(5).values + strength_visual = "" + for val in delta_last_5: + if val > 2 * delta_std: # 大于2个标准差 + strength_visual += "↑↑ " + elif val > 0.5 * delta_std: # 大于0.5个标准差 + strength_visual += "↑ " + elif val < -2 * delta_std: # 小于-2个标准差 + strength_visual += "↓↓ " + elif val < -0.5 * delta_std: # 小于-0.5个标准差 + strength_visual += "↓ " + else: + strength_visual += "→ " + data_text += f"订单流强弱可视化 (最近5分钟): {strength_visual}\n" + data_text += f"当前delta标准差: {delta_std:.2f}\n" + + # 添加最近几条记录的趋势 + data_text += "\n最近几条记录的趋势:\n" + + # 添加最近5条记录的关键指标变化 + for i in range(min(5, len(recent_data))): + idx = -(i+1) + data_text += f"记录 {i+1}: 时间={recent_data['datetime'].iloc[idx]}, 价格={recent_data['close'].iloc[idx]}, " + data_text += f"订单流净值={recent_data['delta'].iloc[idx]}, 堆积={recent_data['dj'].iloc[idx]}\n" + + # 添加当前持仓信息,使用新的止盈止损字典 + data_text += "\n当前持仓状态:\n" + + # 获取该合约的止盈止损信息 + stops = self.stop_order_dict.get(instrument_id, { + 'long': {'position': 0, 'entry_price': 0, 'stop_loss': 0, 'take_profit': 0, 'trailing_stop': 0}, + 'short': {'position': 0, 'entry_price': 0, 'stop_loss': 0, 'take_profit': 0, 'trailing_stop': 0} + }) + + # 获取多头和空头持仓信息 + long_pos = stops.get('long', {}).get('position', 0) + short_pos = stops.get('short', {}).get('position', 0) + + # 判断当前持仓方向 + if long_pos > 0: + data_text += f"持仓方向: 多头\n" + data_text += f"持仓数量: {long_pos}\n" + data_text += f"开仓价格: {stops['long']['entry_price']}\n" + data_text += f"止损价格: {stops['long']['stop_loss']}\n" + data_text += f"止盈价格: {stops['long']['take_profit']}\n" + data_text += f"跟踪止损价: {stops['long']['trailing_stop']}\n" + + # 计算当前盈亏 + current_price = recent_data['close'].iloc[-1] + profit_percent = (current_price - stops['long']['entry_price']) / stops['long']['entry_price'] * 100 + data_text += f"当前盈亏: {profit_percent:.2f}%\n" + elif short_pos > 0: + data_text += f"持仓方向: 空头\n" + data_text += f"持仓数量: {short_pos}\n" + data_text += f"开仓价格: {stops['short']['entry_price']}\n" + data_text += f"止损价格: {stops['short']['stop_loss']}\n" + data_text += f"止盈价格: {stops['short']['take_profit']}\n" + data_text += f"跟踪止损价: {stops['short']['trailing_stop']}\n" + + # 计算当前盈亏 + current_price = recent_data['close'].iloc[-1] + profit_percent = (stops['short']['entry_price'] - current_price) / stops['short']['entry_price'] * 100 + data_text += f"当前盈亏: {profit_percent:.2f}%\n" + else: + data_text += "持仓方向: 空仓\n" + data_text += "持仓数量: 0\n" + + # 添加风险管理参数信息 + data_text += "\n风险管理参数设置:\n" + data_text += f"固定止损百分比: {self.fixed_stop_loss_percent * 100:.2f}%\n" + data_text += f"跟踪止损百分比: {self.trailing_stop_percent * 100:.2f}%\n" + + # 添加交易建议提示 + data_text += "\n请根据以上信息,分析当前市场状态并给出交易建议。需要考虑:\n" + data_text += "1. 当前持仓状态是否合理\n" + data_text += "2. 是否需要调整止损止盈位置\n" + data_text += "3. 是否需要平仓或反手\n" + data_text += "4. 是否适合开新仓\n" + data_text += "5. 是否需要调整跟踪止损百分比参数(范围建议:0.0001-0.001)\n" + data_text += "6. 是否出现抄底摸顶机会\n" + data_text += "7. 是否存在日内波段交易机会\n" + + return data_text + + def update_stop_order_dict(self, instrument_id, direction, position, entry_price=None, stop_loss=None, take_profit=None, trailing_stop=None): + """更新止损止盈信息""" + # 初始化合约的止损止盈字典 + if instrument_id not in self.stop_order_dict: + self.stop_order_dict[instrument_id] = { + 'long': {'position': 0, 'entry_price': 0, 'stop_loss': 0, 'take_profit': 0, 'trailing_stop': 0}, + 'short': {'position': 0, 'entry_price': 0, 'stop_loss': 0, 'take_profit': 0, 'trailing_stop': 0} + } + + # 获取当前值 + current_values = self.stop_order_dict[instrument_id][direction].copy() + + # 更新值 + if position is not None: + self.stop_order_dict[instrument_id][direction]['position'] = position + if entry_price is not None: + self.stop_order_dict[instrument_id][direction]['entry_price'] = entry_price + if stop_loss is not None: + self.stop_order_dict[instrument_id][direction]['stop_loss'] = stop_loss + if take_profit is not None: + self.stop_order_dict[instrument_id][direction]['take_profit'] = take_profit + if trailing_stop is not None: + self.stop_order_dict[instrument_id][direction]['trailing_stop'] = trailing_stop + + # 记录变化值 + updated_values = self.stop_order_dict[instrument_id][direction] + change_log = f"更新{instrument_id} {direction}头寸止损止盈: " + changes = [] + + if position is not None and position != current_values['position']: + changes.append(f"仓位: {current_values['position']} -> {position}") + if entry_price is not None and entry_price != current_values['entry_price']: + changes.append(f"入场价: {current_values['entry_price']} -> {entry_price}") + if stop_loss is not None and stop_loss != current_values['stop_loss']: + changes.append(f"止损价: {current_values['stop_loss']} -> {stop_loss}") + if take_profit is not None and take_profit != current_values['take_profit']: + changes.append(f"止盈价: {current_values['take_profit']} -> {take_profit}") + if trailing_stop is not None and trailing_stop != current_values['trailing_stop']: + changes.append(f"跟踪止损价: {current_values['trailing_stop']} -> {trailing_stop}") + + if changes: + change_log += ", ".join(changes) + STOPLOSS_LOGGER.info(change_log) + + # 保存到文件 + self.save_stop_orders_to_file(instrument_id) + + def save_stop_orders_to_file(self, instrument_id): + """将止盈止损信息保存到文件""" + # 使用完整的合约代码 + symbol = str(instrument_id) + folder_path = "traderdata" + file_path = os.path.join(folder_path, f"{symbol}_stops.json") + + # 如果文件夹不存在则创建 + if not os.path.exists(folder_path): + os.makedirs(folder_path, exist_ok=True) + + # 保存字典到JSON文件 + with open(file_path, 'w') as f: + json.dump(self.stop_order_dict.get(instrument_id, {}), f, indent=4) + + # 获取该合约的止盈止损信息 + stops = self.stop_order_dict.get(instrument_id, { + 'long': {'position': 0, 'entry_price': 0, 'stop_loss': 0, 'take_profit': 0, 'trailing_stop': 0}, + 'short': {'position': 0, 'entry_price': 0, 'stop_loss': 0, 'take_profit': 0, 'trailing_stop': 0} + }) + + # 打印详细信息 + print(f"\n===== 已更新止盈止损信息: {instrument_id} =====") + print(f"多头持仓: {stops['long']['position']} 手") + print(f"多头入场价: {stops['long']['entry_price']}") + print(f"多头止损价: {stops['long']['stop_loss']}") + print(f"多头止盈价: {stops['long']['take_profit']}") + print(f"多头跟踪止损: {stops['long']['trailing_stop']}") + print(f"空头持仓: {stops['short']['position']} 手") + print(f"空头入场价: {stops['short']['entry_price']}") + print(f"空头止损价: {stops['short']['stop_loss']}") + print(f"空头止盈价: {stops['short']['take_profit']}") + print(f"空头跟踪止损: {stops['short']['trailing_stop']}") + print("======================================\n") + + def load_stop_orders_from_file(self, instrument_id): + """从文件加载止盈止损信息""" + # 如果合约ID已经在字典中,直接返回,避免重复加载 + if instrument_id in self.stop_order_dict: + return True + + # 使用完整的合约代码 + symbol = str(instrument_id) + folder_path = "traderdata" + file_path = os.path.join(folder_path, f"{symbol}_stops.json") + + if os.path.exists(file_path): + try: + with open(file_path, 'r') as f: + stops_data = json.load(f) + + # 更新字典 + self.stop_order_dict[instrument_id] = stops_data + print(f"首次加载止盈止损信息: {instrument_id}") + return True + except Exception as e: + print(f"加载止盈止损信息失败: {e}") + + # 如果文件不存在,初始化空字典结构 + if instrument_id not in self.stop_order_dict: + self.stop_order_dict[instrument_id] = { + 'long': {'position': 0, 'entry_price': 0, 'stop_loss': 0, 'take_profit': 0, 'trailing_stop': 0}, + 'short': {'position': 0, 'entry_price': 0, 'stop_loss': 0, 'take_profit': 0, 'trailing_stop': 0} + } + print(f"初始化止盈止损结构: {instrument_id}") + + return False + + def check_stop_conditions(self, data): + """检查是否满足止盈止损条件""" + instrument_id = data['InstrumentID'].decode() + + # 如果该合约不在止盈止损字典中,直接返回 + if instrument_id not in self.stop_order_dict: + return + + current_bid = float(data['BidPrice1']) # 当前买价 + current_ask = float(data['AskPrice1']) # 当前卖价 + + stops = self.stop_order_dict[instrument_id] + + # 检查多头止盈止损 + if stops['long']['position'] > 0: + entry_price = stops['long']['entry_price'] # 获取开仓价 + + # 检查止损 + if stops['long']['stop_loss'] > 0 and current_bid <= stops['long']['stop_loss']: + print(f"触发多头止损: {instrument_id}, 价格: {current_bid}, 止损价: {stops['long']['stop_loss']}") + self.insert_order(data['ExchangeID'], data['InstrumentID'], current_bid-self.py, + stops['long']['position'], b'1', b'3') + # 清空多头持仓信息 + self.clear_position_info(instrument_id, 'long') + self.pos = 0 # 更新全局持仓状态 + + # 检查跟踪止损 - 确保只在价格高于开仓价且低于跟踪止损价时触发 + elif stops['long']['trailing_stop'] > 0 and current_bid < stops['long']['trailing_stop'] and current_bid > entry_price: + print(f"触发多头跟踪止损: {instrument_id}, 价格: {current_bid}, 跟踪止损价: {stops['long']['trailing_stop']}, 开仓价: {entry_price}") + self.insert_order(data['ExchangeID'], data['InstrumentID'], current_bid-self.py, + stops['long']['position'], b'1', b'3') + # 清空多头持仓信息 + self.clear_position_info(instrument_id, 'long') + self.pos = 0 # 更新全局持仓状态 + + # 检查止盈 + elif stops['long']['take_profit'] > 0 and current_bid >= stops['long']['take_profit']: + print(f"触发多头止盈: {instrument_id}, 价格: {current_bid}, 止盈价: {stops['long']['take_profit']}") + self.insert_order(data['ExchangeID'], data['InstrumentID'], current_bid-self.py, + stops['long']['position'], b'1', b'3') + # 清空多头持仓信息 + self.clear_position_info(instrument_id, 'long') + self.pos = 0 # 更新全局持仓状态 + + # 更新跟踪止损价 - 严格限制只在价格高于开仓价时更新 + elif current_bid > entry_price and stops['long']['trailing_stop'] > 0: + # 只有当前价格比之前设置的跟踪止损价高一定幅度时才更新 + new_trailing_stop = current_bid * (1 - self.trailing_stop_percent) + + # 判断是否应该更新跟踪止损价 + should_update = False + + # 条件1: 新的跟踪止损价必须高于当前的跟踪止损价(跟踪止损上移) + if new_trailing_stop > stops['long']['trailing_stop']: + # 条件2: 如果存在止损价(非0),则新的跟踪止损价不应该触及人工设置的止损价 + if stops['long']['stop_loss'] == 0 or new_trailing_stop < stops['long']['stop_loss']: + should_update = True + + if should_update: + self.update_stop_order_dict(instrument_id, 'long', None, None, None, None, new_trailing_stop) + print(f"更新多头跟踪止损: {instrument_id}, 新跟踪止损价: {new_trailing_stop}, 开仓价: {entry_price}") + + # 检查空头止盈止损 + if stops['short']['position'] > 0: + entry_price = stops['short']['entry_price'] # 获取开仓价 + + # 检查止损 + if stops['short']['stop_loss'] > 0 and current_ask >= stops['short']['stop_loss']: + print(f"触发空头止损: {instrument_id}, 价格: {current_ask}, 止损价: {stops['short']['stop_loss']}") + self.insert_order(data['ExchangeID'], data['InstrumentID'], current_ask+self.py, + stops['short']['position'], b'0', b'3') + # 清空空头持仓信息 + self.clear_position_info(instrument_id, 'short') + self.pos = 0 # 更新全局持仓状态 + + # 检查跟踪止损 - 确保只在价格低于开仓价且高于跟踪止损价时触发 + elif stops['short']['trailing_stop'] > 0 and current_ask > stops['short']['trailing_stop'] and current_ask < entry_price: + print(f"触发空头跟踪止损: {instrument_id}, 价格: {current_ask}, 跟踪止损价: {stops['short']['trailing_stop']}, 开仓价: {entry_price}") + self.insert_order(data['ExchangeID'], data['InstrumentID'], current_ask+self.py, + stops['short']['position'], b'0', b'3') + # 清空空头持仓信息 + self.clear_position_info(instrument_id, 'short') + self.pos = 0 # 更新全局持仓状态 + + # 检查止盈 + elif stops['short']['take_profit'] > 0 and current_ask <= stops['short']['take_profit']: + print(f"触发空头止盈: {instrument_id}, 价格: {current_ask}, 止盈价: {stops['short']['take_profit']}") + self.insert_order(data['ExchangeID'], data['InstrumentID'], current_ask+self.py, + stops['short']['position'], b'0', b'3') + # 清空空头持仓信息 + self.clear_position_info(instrument_id, 'short') + self.pos = 0 # 更新全局持仓状态 + + # 更新跟踪止损价 - 严格限制只在价格低于开仓价时更新 + elif current_ask < entry_price and stops['short']['trailing_stop'] > 0: + # 只有当前价格比之前设置的跟踪止损价低一定幅度时才更新 + new_trailing_stop = current_ask * (1 + self.trailing_stop_percent) + + # 判断是否应该更新跟踪止损价 + should_update = False + + # 条件1: 新的跟踪止损价必须低于当前的跟踪止损价(跟踪止损下移)或当前跟踪止损价为0 + if new_trailing_stop < stops['short']['trailing_stop'] or stops['short']['trailing_stop'] == 0: + # 条件2: 如果存在止损价(非0),则新的跟踪止损价不应该触及人工设置的止损价 + if stops['short']['stop_loss'] == 0 or new_trailing_stop > stops['short']['stop_loss']: + should_update = True + + if should_update: + self.update_stop_order_dict(instrument_id, 'short', None, None, None, None, new_trailing_stop) + print(f"更新空头跟踪止损: {instrument_id}, 新跟踪止损价: {new_trailing_stop}, 开仓价: {entry_price}") + + #保存数据 + + def clear_position_info(self, instrument_id, direction): + """ + 清空指定合约和方向的持仓信息 + + Args: + instrument_id: 合约ID + direction: 方向 'long' 或 'short' 或 'all' + """ + # 确保合约ID在字典中存在 + if instrument_id not in self.stop_order_dict: + return + + print(f"开始清空{instrument_id}的{direction}持仓信息") + if direction == 'long' or direction == 'all': + # 清空多头持仓信息 + self.stop_order_dict[instrument_id]['long'] = { + 'position': 0, + 'entry_price': 0, + 'stop_loss': 0, + 'take_profit': 0, + 'trailing_stop': 0 + } + # 兼容旧代码 + if direction == 'long': + self.long_trailing_stop_price = 0 + self.sl_long_price = 0 + + if direction == 'short' or direction == 'all': + # 清空空头持仓信息 + self.stop_order_dict[instrument_id]['short'] = { + 'position': 0, + 'entry_price': 0, + 'stop_loss': 0, + 'take_profit': 0, + 'trailing_stop': 0 + } + # 兼容旧代码 + if direction == 'short': + self.short_trailing_stop_price = 0 + self.sl_shor_price = 0 + + # 同步全局持仓状态 + if direction == 'all': + self.pos = 0 + self.long_trailing_stop_price = 0 + self.short_trailing_stop_price = 0 + self.sl_long_price = 0 + self.sl_shor_price = 0 + + # 保存到文件 + try: + self.save_stop_orders_to_file(instrument_id) + self.save_to_csv(instrument_id) + print(f"已成功清空{instrument_id}的{direction}持仓信息并保存") + except Exception as e: + print(f"清空持仓信息时出错: {e}") + +# 修改call_deepseek_model函数,移除JSON格式输出的要求,改为从普通文本响应中提取交易信号。 +def call_deepseek_model(data_df, trader_instance, max_retries=2): + """ + 调用qwq-32b大模型分析订单流数据 + + Args: + data_df: 包含订单流数据的DataFrame + trader_instance: MyTrader实例,用于访问持仓信息 + max_retries: 最大重试次数 + + Returns: + dict: 包含交易信号的字典 + """ + # 直接从环境变量获取API密钥 + api_key = GLOBAL_LLM_CONFIG.get('api_key') + base_url = GLOBAL_LLM_CONFIG.get('base_url') + model_name = GLOBAL_LLM_CONFIG.get('model_name') + + # 检查API密钥是否为空 + if not api_key: + print("错误: API密钥未设置,请在main函数中配置GLOBAL_LLM_CONFIG['api_key']") + return {"action": "不操作", "reason": "API密钥未设置", "confidence": 0, "stop_loss": 0, "take_profit": 0} + + # 将DataFrame转换为可读性好的文本,传递trader_instance + data_text = trader_instance.format_data_for_llm(data_df) + + # 构建提示词 + prompt = f""" + 作为专注于趋势交易的期货交易员,基于以下市场数据做出交易决策: + + {data_text} + + 请重点考虑以下关键因素: + 1. 均线系统(5、10、20均线)的排列状态和金叉死叉信号 + 2. 价格是否处于明确的上升或下降通道中 + 3. 关键阻力位和支撑位的突破情况及其确认 + 4. 成交量是否配合价格趋势(上涨时放量,下跌时同样放量) + 5. 动量指标(MACD、KDJ等)的走势和信号 + 6. 订单流趋势与主力资金方向的一致性 + 7. 市场多空力量对比的持续性变化 + 8. 当前趋势的强度与持续时间评估 + + 【风险控制原则】: + - 严格控制每笔交易亏损不超过本金的1% + - 趋势交易的止损位应设置在次级回调位或关键技术位之下,通常为开仓价的0.5%-0.1% + - 使用移动止损机制跟踪趋势发展,锁定利润 + - 避免在盘整区间内频繁交易,等待明确的突破信号 + + 请根据市场状态和持仓情况,给出明确的交易指令: + 1. 交易方向: 不操作/开多/开空/平多/平空/平多开空/平空开多 + 2. 执行理由: 详细说明趋势特征、突破信号、动量变化和持续性评估 + 3. 置信度: 1-10的数字,反映趋势信号的清晰度,必须是整数 + 4. 止损价: 明确的止损价格(必须是数字),设置在关键支撑/阻力位附近 + 5. 止盈价: 明确的首个止盈目标(必须是数字),应至少是止损距离的1.5倍 + 6. 跟踪止损百分比: 0.0001-0.001之间的数字,用于设置移动止损追踪趋势 + + 请按以下格式返回交易决策,格式必须严格匹配: + action: 不操作/开多/开空/平多/平空/平多开空/平空开多 + reason: 交易理由 + confidence: 置信度(1-10) + stop_loss: 止损价 + take_profit: 止盈价 + trailing_percent: 跟踪止损百分比(0.0001-0.001) + """ + + system_prompt = {"role": "system", + "content": "你是一位专注于趋势交易的期货交易员,擅长识别和追踪强势趋势。你的交易风格注重动量和突破信号,善于在确认趋势后顺势而为,合理管理风险的同时最大化捕捉趋势利润。你特别关注均线系统、趋势线、成交量确认和动量指标,能精准判断趋势的强度和持续性。你擅长使用移动止损保护利润,在趋势延续时持有头寸,在趋势减弱时及时退出。请根据指定格式返回交易决策。"} + + # 添加重试机制 + retries = 0 + while retries <= max_retries: + try: + # 如果不是第一次尝试,输出重试信息 + if retries > 0: + print(f"正在进行第 {retries} 次重试...") + + # 调试信息 + print(f"使用API参数: base_url={base_url}, model={model_name}") + + # 添加明显的提示信息,表示正在调用大模型API + print("\n============================================") + print("【正在调用大模型API进行交易分析,请稍候...】") + print("============================================\n") + + # 记录开始时间 + api_start_time = time.time() + + # 使用OpenAI客户端格式调用API + client = OpenAI(api_key=api_key, base_url=base_url) + + # 发起流式请求 + response = client.chat.completions.create( + model=model_name, + messages=[ + system_prompt, + {"role": "user", "content": prompt} + ], + temperature=0.1, + stream=False, # 不启用流式模式 + max_tokens=8192, + timeout=60 + ) + + # 提取模型响应内容 + model_response = response.choices[0].message.content + + # 计算耗时 + api_elapsed = time.time() - api_start_time + print(f"\n\n模型响应总耗时: {api_elapsed:.2f}秒") + print("完整响应前100字符: " + model_response[:100] + "...") + + # 添加明显的提示信息,表示API调用已完成 + print("\n============================================") + print("【大模型API调用完成】") + print("============================================\n") + + # 从文本中解析出交易信号 + try: + trading_signal = parse_trading_signal(model_response) + return trading_signal + except Exception as parse_err: + print(f"解析模型响应出错: {parse_err}") + # 尝试从自由文本中提取关键信息 + return extract_trading_signal_from_text(model_response) + + except Exception as e: + retries += 1 + if retries <= max_retries: + print(f"调用大模型API出错: {e}") + print(f"将在3秒后重试...") + time.sleep(3) # 等待3秒后重试 + else: + print(f"已达到最大重试次数 ({max_retries}),调用大模型API失败") + print(f"错误详情: {e}") + print("\n请检查以下几点:") + print("1. API密钥格式是否正确,应以'sk-'开头") + print("2. 确认已安装最新版本的openai库: pip install --upgrade openai") + print("3. 确认您的API密钥对应的模型是否为deepseek-reasoner") + # 返回默认的不操作信号 + return {"action": "不操作", "reason": f"API调用失败: {str(e)[:100]}", "confidence": 0, "stop_loss": 0, "take_profit": 0} + + # 如果所有重试都失败了,返回默认值 + return {"action": "不操作", "reason": "API调用重试耗尽", "confidence": 0, "stop_loss": 0, "take_profit": 0} + +def parse_trading_signal(text): + """ + 从文本格式的模型响应中解析出交易信号 + + Args: + text: 模型响应文本 + + Returns: + dict: 包含交易信号的字典 + """ + lines = text.strip().split('\n') + trading_signal = {} + + for line in lines: + if ':' in line: + key, value = line.split(':', 1) + key = key.strip().lower() + value = value.strip() + + if key == 'action': + trading_signal['action'] = value + elif key == 'reason': + trading_signal['reason'] = value + elif key == 'confidence': + try: + trading_signal['confidence'] = int(value) + except ValueError: + # 尝试从文本中提取数字 + import re + match = re.search(r'\d+', value) + if match: + trading_signal['confidence'] = int(match.group()) + else: + trading_signal['confidence'] = 0 + elif key == 'stop_loss': + try: + trading_signal['stop_loss'] = float(value) + except ValueError: + # 尝试从文本中提取数字 + import re + match = re.search(r'\d+(\.\d+)?', value) + if match: + trading_signal['stop_loss'] = float(match.group()) + else: + trading_signal['stop_loss'] = 0 + elif key == 'take_profit': + try: + trading_signal['take_profit'] = float(value) + except ValueError: + # 尝试从文本中提取数字 + import re + match = re.search(r'\d+(\.\d+)?', value) + if match: + trading_signal['take_profit'] = float(match.group()) + else: + trading_signal['take_profit'] = 0 + elif key == 'trailing_percent': + try: + value_float = float(value) + # 确保值在合理范围内 0.0001-0.001 + if 0.0001<= value_float <= 0.001: + trading_signal['trailing_percent'] = value_float + else: + # 设置为默认值 + trading_signal['trailing_percent'] = 0.0005 + except ValueError: + trading_signal['trailing_percent'] = 0.0005 + + # 检查是否有缺失的字段,如果有,设置默认值 + if 'action' not in trading_signal: + trading_signal['action'] = '不操作' + if 'reason' not in trading_signal: + trading_signal['reason'] = '未提供理由' + if 'confidence' not in trading_signal: + trading_signal['confidence'] = 0 + if 'stop_loss' not in trading_signal: + trading_signal['stop_loss'] = 0 + if 'take_profit' not in trading_signal: + trading_signal['take_profit'] = 0 + if 'trailing_percent' not in trading_signal: + trading_signal['trailing_percent'] = 0.0005 # 修改默认值 + + return trading_signal + +def extract_trading_signal_from_text(text): + """ + 从自由格式文本中尝试提取交易信号 + + Args: + text: 模型响应文本 + + Returns: + dict: 包含交易信号的字典 + """ + # 默认交易信号 + trading_signal = { + "action": "不操作", + "reason": "无法解析模型响应", + "confidence": 0, + "stop_loss": 0, + "take_profit": 0, + "trailing_percent": 0 # 更新默认的跟踪止损百分比 + } + + # 尝试判断交易方向 + text_lower = text.lower() + if "平多开空" in text_lower: + trading_signal["action"] = "平多开空" + elif "平空开多" in text_lower: + trading_signal["action"] = "平空开多" + elif "开多" in text_lower: + trading_signal["action"] = "开多" + elif "开空" in text_lower: + trading_signal["action"] = "开空" + elif "平多" in text_lower: + trading_signal["action"] = "平多" + elif "平空" in text_lower: + trading_signal["action"] = "平空" + elif "不操作" in text_lower or "观望" in text_lower: + trading_signal["action"] = "不操作" + + # 尝试从文本中提取置信度 + import re + confidence_matches = re.findall(r'置信度[::]\s*(\d+)', text_lower) + if confidence_matches: + try: + trading_signal["confidence"] = int(confidence_matches[0]) + except ValueError: + pass + + # 尝试提取止损价 + stop_loss_matches = re.findall(r'止损价[::]\s*(\d+(\.\d+)?)', text_lower) + if stop_loss_matches: + try: + trading_signal["stop_loss"] = float(stop_loss_matches[0][0]) + except ValueError: + pass + + # 尝试提取止盈价 + take_profit_matches = re.findall(r'止盈价[::]\s*(\d+(\.\d+)?)', text_lower) + if take_profit_matches: + try: + trading_signal["take_profit"] = float(take_profit_matches[0][0]) + except ValueError: + pass + + # 尝试提取跟踪止损百分比 + trailing_matches = re.findall(r'跟踪止损百分比[::]\s*(\d+(\.\d+)?)', text_lower) + if not trailing_matches: + trailing_matches = re.findall(r'跟踪百分比[::]\s*(\d+(\.\d+)?)', text_lower) + + if trailing_matches: + try: + trailing_value = float(trailing_matches[0][0]) + # 判断是否为百分比格式 + if trailing_value >= 0.5 and trailing_value <= 10: + trading_signal["trailing_percent"] = trailing_value / 100 + else: + trading_signal["trailing_percent"] = trailing_value + except ValueError: + pass + + # 提取理由 + reason_matches = re.findall(r'理由[::]\s*(.*?)(?=\n|$)', text_lower) + if reason_matches: + trading_signal["reason"] = reason_matches[0] + + return trading_signal + +# 修改run_trader函数,改为接收统一的配置字典 +def run_trader(broker_id, td_server, investor_id, password, app_id, auth_code, md_queue=None, page_dir='', private_resume_type=2, public_resume_type=2, config=None): + # 设置全局变量 + global GLOBAL_LLM_CONFIG + + # 如果传入了配置字典,直接使用 + if config: + # 使用deepcopy避免潜在的引用问题 + import copy + GLOBAL_LLM_CONFIG = copy.deepcopy(config) + + # 使用位置参数调用MyTrader初始化,因为Cython类不支持关键字参数 + my_trader = MyTrader( + broker_id, + td_server, + investor_id, + password, + app_id, + auth_code, + md_queue, + page_dir, # 使用修复后的日志目录路径 + private_resume_type, + public_resume_type + ) + + # 设置历史数据加载参数 + my_trader.load_history = GLOBAL_LLM_CONFIG['load_history'] + my_trader.history_rows = GLOBAL_LLM_CONFIG['history_rows'] + my_trader.trader_rows = GLOBAL_LLM_CONFIG['trader_rows'] + my_trader.Lots = GLOBAL_LLM_CONFIG['Lots'] + my_trader.Join() + +def ceshiapi(api_key): + # 测试API连接 + print(f"测试API连接,使用密钥: {api_key[:5]}...{api_key[-5:]}") + try: + client = OpenAI(api_key=api_key, base_url=GLOBAL_LLM_CONFIG['base_url'] ) + response = client.chat.completions.create( + model=GLOBAL_LLM_CONFIG['model_name'], + messages=[ + {"role": "system", "content": "你是一个助手"}, + {"role": "user", "content": "测试"} + ], + stream=False, # 新增此行 + max_tokens=10 + ) + print(f"API连接测试成功") + except Exception as e: + print(f"API连接测试失败: {e}") + import traceback + traceback.print_exc() + +def clean_log_directory(log_dir="./log", timeout_seconds=5): + """ + 清理日志目录内的所有文件和子目录,具有超时机制和健壮的异常处理 + + 参数: + log_dir (str): 日志目录路径,默认为"./log" + timeout_seconds (int): 清理操作的最大等待时间(秒),默认为5秒 + + 返回: + bool: 清理操作是否成功完成(未超时且无严重错误) + """ + + print(f"开始清理日志目录: {log_dir}") + success = True + + if os.path.exists(log_dir): + # 设置超时机制,避免长时间阻塞 + start_time = time.time() + + try: + # 遍历并删除log目录下的所有文件和子目录 + for item in os.listdir(log_dir): + # 检查是否超时 + if time.time() - start_time > timeout_seconds: + print(f"清理操作超过{timeout_seconds}秒,中断清理") + success = False + break + + item_path = os.path.join(log_dir, item) + try: + if os.path.isfile(item_path): + os.unlink(item_path) + elif os.path.isdir(item_path): + shutil.rmtree(item_path, ignore_errors=True) + print(f"已清理: {item_path}") + except Exception as e: + print(f"清理 {item_path} 时出错: {e}") + # 记录错误但继续处理其他文件 + except Exception as e: + print(f"清理log目录时出现意外错误: {e}") + success = False + else: + # 如果log目录不存在,则创建它 + try: + os.makedirs(log_dir) + print(f"创建日志目录: {log_dir}") + except Exception as e: + print(f"创建日志目录失败: {e}") + success = False + + if success: + print(f"日志目录清理完成: {log_dir}") + else: + print(f"日志目录清理未完全完成: {log_dir}") + + return success + +if __name__ == '__main__': + #公众号:松鼠Quant + #主页:www.quant789.com + #本策略仅作学习交流使用,实盘交易盈亏投资者个人负责!!! + #版权归松鼠Quant所有,禁止转发、转卖源码违者必究。 + + # 清理日志目录 + clean_log_directory(log_dir="./log", timeout_seconds=10) # 可以调整超时时间 + # 创建临时工作目录(在log文件夹内) + timestamp = int(time.time()) + temp_md_dir = f"./log/user_md_{timestamp}" + temp_td_dir = f"./log/user_td_{timestamp}" + + '''============================================================策略参数填写区============================================================''' + + # 配置大模型参数 o3 代理地址: https://2233.ai/i/9ONWNBDK + # deepseek模型地址:https://www.deepseek.com/ 右上角进入API开放平台创建APIKEY + + api_key = "" #配置大模型API密钥 + api_url = "https://api.deepseek.com" #配置大模型API地址 + api_model = "deepseek-chat" # 大模型名称 + + GLOBAL_LLM_CONFIG['api_key'] = api_key + GLOBAL_LLM_CONFIG['base_url'] = api_url + GLOBAL_LLM_CONFIG['model_name'] = api_model + ceshiapi(api_key) # 测试API连接 + + # 历史数据加载配置 + GLOBAL_LLM_CONFIG['load_history'] = True # 是否加载历史数据 + GLOBAL_LLM_CONFIG['history_rows'] = 50 # 用于分析的历史数据行数 + GLOBAL_LLM_CONFIG['trader_rows'] = 10 # 用于分析的订单流数据最少数量 + GLOBAL_LLM_CONFIG['bar_resample_rule'] = '3T' # 3分钟K线 + GLOBAL_LLM_CONFIG['Lots'] = 1 # 手数 + + '''============================================================个人填写信息区============================================================''' + + # simnow的future_account字典,如果实盘请注释掉simnow的future_account字典 + future_account = get_simulate_account( + investor_id='', #Simnow的账号,注意不是注册账号,是网站登录SIMNOW后,显示的投资者ID + password='', #Simnow的密码,你注册时填写的密码 + server_name='电信1',# 电信1、电信2、移动、TEST、N视界 + subscribe_list= [b'au2506'], # 订阅合约列表,注意是bytes类型,例如b'au2506' + md_flow_path=temp_md_dir, + td_flow_path=temp_td_dir, + ) + + + #实盘用这个,切记注释掉上方simnow的future_account字典 + # future_account = FutureAccount( + # broker_id='', # 期货公司BrokerID + # server_dict={'TDServer': "ip:port", 'MDServer': 'ip:port'}, # TDServer为交易服务器,MDServer为行情服务器。服务器地址格式为"ip:port。" + # reserve_server_dict={}, # 备用服务器地址 + # investor_id='', # 账户 + # password='', # 密码 + # app_id='simnow_client_test', # 认证使用AppID + # auth_code='0000000000000000', # 认证使用授权码 + # subscribe_list=[b'au2506'], # 订阅合约列表 + # md_flow_path=temp_md_dir, # MdApi流文件存储地址,默认MD_LOCATION + # td_flow_path=temp_td_dir, # TraderApi流文件存储地址,默认TD_LOCATION + # ) + + '''============================================================个人填写信息区============================================================''' + + print('开始', len(future_account.subscribe_list)) + # 共享队列 + share_queue = Queue(maxsize=200) + + # 行情进程 + md_process = Process(target=run_tick_engine, args=(future_account, [share_queue])) + + # 使用深拷贝创建一个完全独立的配置副本 + import copy + config_copy = copy.deepcopy(GLOBAL_LLM_CONFIG) + + # 交易进程 + trader_process = Process(target=run_trader, args=( + future_account.broker_id, + future_account.server_dict['TDServer'], + future_account.investor_id, + future_account.password, + future_account.app_id, + future_account.auth_code, + share_queue, + temp_td_dir, + 2, # private_resume_type + 2, # public_resume_type + config_copy, + )) + + md_process.start() + trader_process.start() + + md_process.join() + trader_process.join() diff --git a/1.交易策略/999.其他策略/4.松鼠SF20_基于LLM的订单流日内交易策略/使用文档/4.14版本_new/定时启动.py b/1.交易策略/999.其他策略/4.松鼠SF20_基于LLM的订单流日内交易策略/使用文档/4.14版本_new/定时启动.py new file mode 100644 index 0000000..6925896 --- /dev/null +++ b/1.交易策略/999.其他策略/4.松鼠SF20_基于LLM的订单流日内交易策略/使用文档/4.14版本_new/定时启动.py @@ -0,0 +1,53 @@ +import subprocess +import schedule +import time +from datetime import datetime + +# 定义要启动的文件 +files_to_run = ['vip20_orderflow.py'] + + +def run_scripts(): + print("启动程序...") + for file in files_to_run: + time.sleep(1) + # 使用subprocess模块运行命令 + subprocess.Popen(['start', 'cmd', '/k', 'python', file], shell=True) + print(file) + print(datetime.now(),'程序重新启动完成,等待明天关闭重启') + + +def close_scripts(): + print("关闭程序...") + # 通过创建一个包含关闭指定窗口命令的批处理文件来关闭CMD窗口 + def close_specific_cmd_window(cmd_window_title): + with open("close_cmd_window.bat", "w") as batch_file: + batch_file.write(f'@echo off\nfor /f "tokens=2 delims=," %%a in (\'tasklist /v /fo csv ^| findstr /i "{cmd_window_title}"\') do taskkill /pid %%~a') + + # 运行批处理文件 + subprocess.run("close_cmd_window.bat", shell=True) + + + # 循环关闭所有脚本对应的CMD窗口 + for title in files_to_run: + close_specific_cmd_window(title) + print(datetime.now(),'已关闭程序,等待重新运行程序') + + + +# 设置定时任务,关闭程序 +schedule.every().day.at("15:20").do(close_scripts) +schedule.every().day.at("02:45").do(close_scripts) + +# 设置定时任务,启动程序 +schedule.every().day.at("08:55").do(run_scripts) +schedule.every().day.at("20:55").do(run_scripts) + + + +# 保持脚本运行,等待定时任务触发 + #zzg_quant +while True: + schedule.run_pending() + time.sleep(1) + #zzg_quant diff --git a/temp/2025年松鼠策略/专享策略20_基于LLM的订单流日内交易策略.zip b/1.交易策略/999.其他策略/4.松鼠SF20_基于LLM的订单流日内交易策略/原始文档/专享策略20_基于LLM的订单流日内交易策略.zip similarity index 100% rename from temp/2025年松鼠策略/专享策略20_基于LLM的订单流日内交易策略.zip rename to 1.交易策略/999.其他策略/4.松鼠SF20_基于LLM的订单流日内交易策略/原始文档/专享策略20_基于LLM的订单流日内交易策略.zip