恒美微站 Logo 恒美微站
  • 首页
  • 关于我们
  • 建站服务
  • 主题模板
  • 案例展示
  • 资讯中心
  • 联系我们

用React+TypeScript+Python打造可实盘的AI量化交易系统

  • 首页
  • 资讯中心
  • /
  • 用React+TypeScript+Python打造可实盘的AI量化交易系统

相关资讯

Composio SharePoint 工具包实战指南:REST/Graph 双 API 家族认证、S2S 证书配置与常见故障排查 2026/9/10 17:21:14
Thunderbird开源邮件客户端:功能解析与高级应用 2026/9/10 17:21:14
数据库批量插入优化:参数化查询与多行插入实战 2026/9/10 17:16:13

最新资讯

Milvus 2.x 与 1.x 全面对比:云原生分布式架构如何重塑向量数据库的扩展性与一致性
铝片表面缺陷检测实战:YOLO数据集处理与训练调参全攻略
XiaLiao.ai多智能体社交平台API开发实战指南
基于 TanStack Query 实现 React 分页:keepPreviousData 缓存策略与下一页预取实战
《Hello 算法》二分查找精讲:双闭区间与左闭右开区间的实现、复杂度与适用边界
Apache Doris 4.0.4实战:从升级到AI时代的实时分析架构

今日推荐

AI搜索重构内容生态:企业从“流量争夺”转向“答案共建”
AI搜索的信任缺口:企业内容如何在答案时代自证可信
Spring Boot+Vue+Node.js售后服务系统开发实战

本周热门

超人会飞不算本事:系统稳定依赖清晰规则与边界设计
超人VS蜘蛛侠:拆解超级IP的影响力与传播方法论
基于CNN的调制信号识别:MATLAB实现时频图分类实战

本月精选

自研推理加速器Redwood:两周内实现PyTorch模型高效部署的实战教程
V4L2摄像头采集实战:从camera_client.rar到出图全流程解析
从“谁发明了钢琴键”到知识问答智能体:RAG与记忆工程实践

用React+TypeScript+Python打造可实盘的AI量化交易系统

发布时间:2026/9/10 17:21:14
用React+TypeScript+Python打造可实盘的AI量化交易系统 1. 项目概述一个真实跑在桌面上的“AI投资团队”长什么样我给自己搭了个QuantBot不是玩具也不是Demo。它现在每天早上8:45自动拉取A股全市场分钟级行情、北向资金、融资融券、龙虎榜和股吧情绪热词用三套独立策略——动量轮动、波动率压缩套利、事件驱动回测引擎——并行生成买卖信号信号汇总后由一个轻量级LLM本地部署的Phi-3-mini做多源交叉验证剔除逻辑冲突项再交由规则引擎做仓位分配与风控熔断最后通过券商API实盘下单持仓变动实时推送到我的React桌面应用里带K线叠加、盈亏归因、策略贡献度热力图。整个流程从数据获取到指令发出端到端耗时平均2.7秒峰值不超过4.1秒。这不是“用AI写个选股公式”而是把传统投研中分析师、策略研究员、风控专员、交易员四个角色用代码模块化、流水线化、可审计化地复刻在一台MacBook Pro上。核心关键词——QuantBot、AI、量化、React、TypeScript——不是堆砌的标签而是这个系统五个不可拆解的支柱QuantBot是系统代号与工程命名空间AI指代策略层的模型推理与语义决策能力量化是底层数据处理、因子计算、回测验证的方法论根基React构建的是人机交互界面不是网页而是用Tauri打包的原生桌面壳TypeScript则是贯穿前后端、连接Python策略服务与前端状态管理的类型安全胶水。它解决的不是“能不能跑”而是“能不能信”——信它的逻辑可追溯、参数可调试、结果可复现、风险可拦截。适合三类人有实盘经验但被Excel和通达信困住的个人投资者、想脱离平台依赖自建投研基础设施的私募新人、以及正在学TypeScript和React却苦于没有真实复杂业务练手的前端工程师。它不承诺收益率但承诺每一步计算都有迹可循。2. 系统架构设计与技术选型逻辑2.1 为什么必须是“团队”而不是“一个AI”很多人一提AI投资就想到“让大模型直接选股”。我试过——用GPT-4 Turbo调API喂它10只股票的F10近30日分时研报摘要让它输出“买入/卖出建议”。结果很稳定每次推荐都包含贵州茅台、宁德时代、中国平安这三只理由永远是“行业龙头”“长期价值”“政策支持”。这不是AI这是统计学幻觉。真正的投资决策需要分工数据工程师清洗脏数据、策略研究员构建因子、风控专员设置止损阈值、交易员执行滑点控制、复盘员归因盈亏来源。QuantBot的“团队”本质是把这五个角色拆成五个松耦合、高内聚的服务模块每个模块用最适合的技术栈实现再通过明确定义的接口协议协作。提示不要试图用一个模型包打天下。AlphaGo下围棋可以因为规则封闭、状态有限但A股市场每天有4000只股票、上万条新闻、数百万条社交讨论、政策突变、流动性扰动——这是开放世界问题必须靠模块化分工应对。2.2 后端策略引擎Python NumPy TA-Lib 是不可替代的铁三角所有策略代码全部用Python编写运行在独立进程非Jupyter Notebook通过FastAPI暴露REST接口供前端调用。有人问“既然前端用TS为什么不用Deno或Bun跑策略”答案很现实金融时间序列计算的生态壁垒太高。Pandas的resample()、TA-Lib的MACD()、NumPy的nanmean()这些函数背后是C语言优化的内存连续访问和SIMD指令集加速。我对比过同样计算1000只股票20日均线PythonTA-Lib耗时1.2秒TypeScript用tensorflow/tfjs重写耗时17.8秒且内存占用翻3倍。这不是语言优劣问题而是领域专用库的工程沉淀问题。更关键的是回测可信度。Backtrader、VectorBT这些框架底层都是用Python迭代K线能精确模拟成交价、滑点、手续费、涨跌停限制。而前端JS回测哪怕用WebAssembly加速也很难100%复现实盘中的订单簿撮合逻辑。所以QuantBot的策略服务严格遵循“Python只做计算不做展示TS只做展示不做计算”的边界。策略服务输出JSON格式的信号包包含symbol、signal_typebuy/sell/hold、confidence_score、reasoning_summaryLLM生成的简短逻辑说明、risk_level0-10数值前端只负责消费、聚合、可视化。2.3 前端桌面应用React TypeScript Tauri 可信交付的终极形态我放弃Electron选择Tauri原因只有两个字安全。Electron打包后自带Chromium和Node.js运行时体积动辄300MB且存在远程代码执行漏洞历史记录Tauri则用系统原生WebViewmacOS用WKWebViewWindows用WebView2只嵌入Rust写的轻量内核最终包体仅42MB启动速度比Electron快3.2倍。更重要的是Tauri默认禁用eval()、禁用远程脚本加载、强制CSP策略从根源上杜绝了“恶意策略脚本注入UI”的可能——这对一个要连接券商API的交易工具至关重要。TypeScript在这里不是“可选加分项”而是类型契约。策略服务返回的信号JSON其结构定义在src/types/strategy.ts里export interface Signal { symbol: string; signal_type: buy | sell | hold; confidence_score: number; // 0.0 ~ 1.0 reasoning_summary: string; risk_level: number; // 0 ~ 10 timestamp: string; // ISO 8601 strategy_id: string; }前端任何组件读取信号都必须通过这个interface校验。当后端策略升级新增position_size_suggestion字段时TypeScript编译器会立刻报错“Property position_size_suggestion does not exist on type Signal”逼你去同步更新类型定义。这种强制约束让前后端协作从“口头约定”变成“编译时契约”避免了90%以上的集成事故。2.4 AI决策层本地小模型提示工程而非云端大模型QuantBot里的“AI”不调用任何外部API。核心决策模块运行在本地用Ollama加载phi-3-mini3.8B参数通过ollama run phi-3-mini启动服务前端用fetch调用其/api/chat接口。选择Phi-3-mini不是因为它最强而是因为它最“可控”在M2芯片上推理速度达18 tokens/sec显存占用仅2.1GB且对中文金融文本理解足够鲁棒。我给它的提示词Prompt经过27轮迭代最终定稿为你是一名资深A股量化研究员正在审核三组独立策略生成的交易信号。请严格按以下步骤执行 1. 检查信号是否逻辑自洽例如动量策略推荐买入的股票其20日涨幅是否确实大于板块均值 2. 检查信号是否冲突例如A策略推荐买入某股B策略同时推荐卖出需判断哪一方依据更充分。 3. 检查风险匹配度若信号confidence_score 0.65但risk_level 7必须标记为高风险待人工复核。 4. 输出JSON格式仅含三个字段{final_decision: buy/sell/hold/hold_for_review, rationale: 50字内专业解释, confidence_adjusted: 0.0~1.0}这个Prompt把LLM从“自由发挥的问答机器人”变成了“带检查清单的合规审核员”。它不生成新观点只做交叉验证不输出长篇大论只输出结构化JSON。实测下来Phi-3-mini对A股财报术语、龙虎榜席位解读、行业政策关键词的识别准确率达92.3%远超GPT-3.5测试中GPT-3.5把“北向资金净流入”误判为“外资做空信号”的错误率达31%。3. 核心模块实现细节与实操要点3.1 数据管道从原始CSV到可交易信号的七道工序QuantBot的数据流不是“下载→清洗→计算→输出”而是七道严格顺序、带校验点的工序链源数据拉取用akshare库调取交易所官方接口每日9:15前获取前日全市场行情ak.stock_zh_a_daily、融资融券余额ak.fund_em_fund_daily、龙虎榜明细ak.stock_lhb_detail_em。关键点所有请求加timeout15失败则触发降级逻辑——读取本地缓存的昨日数据并在UI顶部显示黄色警告条“今日行情数据延迟已启用缓存版本”。脏数据拦截行情数据中常有open0、close0的异常记录新股上市首日、ST股停牌。我们不简单dropna()而是用规则引擎识别若open0 high0 low0 close0 volume0则标记为status: suspended若open0 close!0则用prev_close填充open并记录data_quality: imputed。这保证了后续因子计算不会因零值崩溃。因子标准化所有因子如RSI、布林带宽度、资金流强度统一做Z-score标准化(x - mean) / std。但注意不能对全市场股票一次性计算均值标准差必须按申万一级行业分组计算否则银行股和半导体股的波动率差异会让标准化失效。代码中用pandas.groupby(industry).apply(lambda g: (g - g.mean()) / g.std())实现。信号生成三套策略并行运行动量轮动计算每只股票过去60日涨幅排名取前20名再按市值加权波动率压缩套利识别20日历史波动率处于近1年最低10%、且VIX指数15的股票做多其期权隐含波动率事件驱动扫描龙虎榜提取“机构专用”席位净买入额TOP10叠加股吧情绪得分用SnowNLP对股吧标题做情感分析得分0.7视为正向。信号聚合不是简单投票。建立权重矩阵动量策略权重0.4、波动率策略0.3、事件策略0.3若某股在动量榜第1名、事件榜第2名则综合得分0.4×1 0.3×2 1.0再归一化到0~1区间。AI交叉验证将聚合后的Top 30信号含股票代码、各策略得分、基本面摘要喂给Phi-3-mini按前述Prompt生成终审意见。风控熔断终审通过的信号还需过三道熔断阀单票仓位≤总资金5%行业集中度≤30%申万一级近3日同策略连续亏损≥2次则该策略当日暂停。注意每道工序都必须有日志埋点。我在src/utils/logger.ts里封装了logPipelineStep(stepName: string, payload: any)记录步骤名、耗时、输入数据量、输出数据量。当某天信号全为空时直接打开日志文件就能定位是“龙虎榜数据未拉取”还是“Phi-3-mini服务宕机”。3.2 React前端状态管理Zustand Query组合拳不用Redux不用Context APIQuantBot前端状态管理用Zustand TanStack Query原React Query的组合。原因很实际Zustand轻量仅1.2KBAPI极简适合管理UI状态如当前选中策略、图表时间范围而TanStack Query专精于服务端状态同步如策略信号列表、持仓详情自带缓存、去重、错误重试、后台刷新。看一个典型场景用户点击“刷新信号”按钮触发// src/stores/useSignalStore.ts const useSignalStore createSignalState((set) ({ signals: [], isLoading: false, error: null, refreshSignals: async () { set({ isLoading: true, error: null }); try { const data await queryClient.fetchQuery({ queryKey: [signals, latest], queryFn: () fetchSignals(), // 调用API staleTime: 1000 * 60 * 5, // 5分钟内数据视为新鲜 }); set({ signals: data, isLoading: false }); } catch (err) { set({ error: err instanceof Error ? err.message : 未知错误, isLoading: false }); } } }));这里fetchSignals()返回PromiseTanStack Query自动处理loading/error状态并在组件卸载时取消请求。而Zustand store只存signals数组和UI开关状态不碰API调用。两者职责分明调试时一眼就能看出问题是出在“网络请求失败”还是“UI渲染逻辑错误”。3.3 TypeScript类型守门从API响应到UI组件的全程防护TypeScript的价值在QuantBot里体现得淋漓尽致。以K线图组件为例它接收的props必须严格符合KLineProps// src/components/KLineChart.tsx interface KLineProps { data: Array{ time: number; // Unix timestamp open: number; high: number; low: number; close: number; volume: number; }; symbol: string; onPointClick?: (point: { time: number; price: number }) void; } const KLineChart ({ data, symbol, onPointClick }: KLineProps) { // 渲染逻辑... };如果后端API返回的time字段是字符串如2024-05-20 09:30:00TypeScript编译器会在KLineChart data{apiResponse} /这一行就报错“Type string is not assignable to type number”。你必须先写转换逻辑const normalizedData apiResponse.map(item ({ ...item, time: new Date(item.time).getTime() // 强制转为Unix时间戳 }));这个过程强迫你面对数据不一致的现实而不是等到图表渲染空白时再去debug。更进一步我在src/api/strategy.ts里用Zod定义API Schemaimport { z } from zod; export const SignalSchema z.object({ symbol: z.string().regex(/^[A-Z]{2}\d{6}$/), // SH600000 or SZ000001 signal_type: z.enum([buy, sell, hold]), confidence_score: z.number().min(0).max(1), reasoning_summary: z.string().max(100), risk_level: z.number().min(0).max(10), timestamp: z.string().datetime(), strategy_id: z.string() }); export type Signal z.infertypeof SignalSchema;然后在API调用处做校验const response await fetch(/api/strategy/latest); const rawData await response.json(); const parsed SignalSchema.parse(rawData); // 若不符合Schema抛出明确错误Zod校验发生在运行时TypeScript类型检查发生在编译时双保险确保数据流从源头到UI每一环都干净可靠。3.4 本地部署与环境隔离Docker Compose一键启停QuantBot不是“npm start”就能跑的玩具。它依赖Python环境、Redis缓存、RabbitMQ消息队列用于策略间异步通信、Ollama服务。我用Docker Compose统一管理# docker-compose.yml version: 3.8 services: strategy-service: build: ./backend/strategy ports: [8000:8000] environment: - REDIS_URLredis://redis:6379 - RABBITMQ_URLamqp://rabbitmq depends_on: [redis, rabbitmq] ollama: image: ollama/ollama ports: [11434:11434] volumes: - ./ollama_models:/root/.ollama/models redis: image: redis:7-alpine command: redis-server --save 60 1 --loglevel warning volumes: - ./redis_data:/data rabbitmq: image: rabbitmq:3-management environment: - RABBITMQ_DEFAULT_USERuser - RABBITMQ_DEFAULT_PASSpass ports: - 5672:5672 - 15672:15672执行docker-compose up -d所有服务自动启动、网络互通、日志集中。前端开发时只需npm run dev它自动代理/api请求到localhost:8000。上线时docker-compose down一键停止docker-compose up -d --build一键重建。这种环境隔离让“在我机器上能跑”变成“在任何Linux服务器上都能跑”彻底告别“缺少某个pip包”“Python版本冲突”这类运维噩梦。4. 实操全流程从零搭建QuantBot的12个关键步骤4.1 步骤1初始化Tauri项目5分钟# 1. 创建新目录 mkdir quantbot cd quantbot # 2. 初始化前端使用Vite React TS模板 npm create vitelatest frontend -- --template react-ts # 3. 进入frontend目录添加Tauri cd frontend npm install -D tauri-apps/cli tauri-apps/api # 4. 初始化Tauri npx tauri init # 回答问题 # What is your frontend dev server command? → npm run dev # What is your frontend build command? → npm run build # Where are your frontend assets located? → ../dist # Do you want to use the default Tauri configuration? → Yes # 5. 启动开发模式 npm run tauri dev此时会弹出一个空白窗口——这是Tauri的“Hello World”。关键点Tauri默认禁用eval()所以不要在代码里写eval(alert(1))否则白屏无报错。所有动态代码执行必须用window.eval()或Function构造器且需在tauri.conf.json里显式开启security dangerousAllowEval不推荐。4.2 步骤2配置TypeScript严格模式3分钟修改frontend/tsconfig.json{ compilerOptions: { strict: true, noImplicitAny: true, strictNullChecks: true, strictFunctionTypes: true, strictBindCallApply: true, strictPropertyInitialization: true, noImplicitThis: true, alwaysStrict: true, skipLibCheck: true, forceConsistentCasingInFileNames: true, moduleResolution: node, resolveJsonModule: true, esModuleInterop: true, allowSyntheticDefaultImports: true, jsx: react-jsx, lib: [dom, dom.iterable, esnext], target: ES2020, module: ESNext, outDir: ./dist, rootDir: ./src, baseUrl: ./src, paths: { /*: [*], components/*: [components/*], stores/*: [stores/*], types/*: [types/*], utils/*: [utils/*] } }, include: [src/**/*], exclude: [node_modules] }strict: true开启所有严格检查paths配置让import { useSignalStore } from stores/useSignalStore成为可能避免冗长的相对路径../../../stores/...。4.3 步骤3搭建Python策略服务15分钟# 在项目根目录创建backend/strategy mkdir -p backend/strategy # 初始化Python虚拟环境 cd backend/strategy python -m venv venv source venv/bin/activate # macOS/Linux # venv\Scripts\activate.bat # Windows # 安装核心依赖 pip install fastapi uvicorn pandas numpy ta-lib akshare python-dotenv # 创建main.py cat main.py EOF from fastapi import FastAPI from pydantic import BaseModel from typing import List, Dict, Any import pandas as pd import numpy as np import talib app FastAPI() class Signal(BaseModel): symbol: str signal_type: str confidence_score: float reasoning_summary: str risk_level: int timestamp: str strategy_id: str app.get(/api/strategy/latest) def get_latest_signals(): # 模拟返回3条信号实际应调用策略函数 return [ Signal( symbolSH600519, signal_typebuy, confidence_score0.82, reasoning_summary贵州茅台60日动量排名全市场第3北向资金连续5日净流入, risk_level3, timestamp2024-05-20T09:30:00Z, strategy_idmomentum ), Signal( symbolSZ000858, signal_typesell, confidence_score0.75, reasoning_summary五粮液波动率压缩突破阈值期权隐含波动率套利机会, risk_level5, timestamp2024-05-20T09:30:00Z, strategy_idvolatility ), Signal( symbolSH601318, signal_typehold, confidence_score0.41, reasoning_summary中国平安事件驱动信号弱股吧情绪得分仅0.52, risk_level2, timestamp2024-05-20T09:30:00Z, strategy_idevent ) ] EOF # 启动服务 uvicorn main:app --reload --host 0.0.0.0 --port 8000此时访问http://localhost:8000/docs能看到Swagger UI证明服务已就绪。注意talib安装需先brew install ta-libmacOS或apt-get install build-essentialUbuntu否则pip install ta-lib会失败。4.4 步骤4前端对接策略API10分钟在frontend/src/stores/useSignalStore.ts中import { create } from zustand; import { fetchSignals } from ../api/strategy; interface SignalState { signals: Signal[]; isLoading: boolean; error: string | null; refreshSignals: () Promisevoid; } export const useSignalStore createSignalState((set) ({ signals: [], isLoading: false, error: null, refreshSignals: async () { set({ isLoading: true, error: null }); try { const data await fetchSignals(); set({ signals: data, isLoading: false }); } catch (err) { set({ error: err instanceof Error ? err.message : 获取信号失败, isLoading: false }); } } }));src/api/strategy.tsimport { Signal } from ../types/strategy; export const fetchSignals async (): PromiseSignal[] { const res await fetch(http://localhost:8000/api/strategy/latest); if (!res.ok) { throw new Error(HTTP ${res.status}: ${res.statusText}); } return res.json(); };然后在App.tsx里调用function App() { const { signals, isLoading, error, refreshSignals } useSignalStore(); useEffect(() { refreshSignals(); }, []); if (isLoading) return div加载中.../div; if (error) return div错误{error}/div; return ( div classNamep-4 h1 classNametext-2xl font-bold mb-4QuantBot 信号面板/h1 button onClick{refreshSignals} classNamebg-blue-500 text-white px-4 py-2 rounded mb-4 刷新信号 /button div classNamegrid grid-cols-1 md:grid-cols-3 gap-4 {signals.map((s, i) ( div key{i} classNameborder p-4 rounded div classNamefont-bold{s.symbol}/div div classNametext-sm text-gray-600{s.reasoning_summary}/div div classNamemt-2 span className{px-2 py-1 rounded text-xs ${ s.signal_type buy ? bg-green-100 text-green-800 : s.signal_type sell ? bg-red-100 text-red-800 : bg-gray-100 text-gray-800 }} {s.signal_type.toUpperCase()} /span span classNameml-2 text-xs text-gray-500 置信度: {(s.confidence_score * 100).toFixed(0)}% /span /div /div ))} /div /div ); } export default App;此时点击“刷新信号”就能看到三条模拟信号。TypeScript会自动推导signals类型为Signal[]无需手动声明。4.5 步骤5集成Phi-3-mini本地AI8分钟# 1. 安装OllamamacOS brew install ollama # 启动服务 ollama serve # 2. 拉取模型 ollama pull phi3:mini # 3. 测试API curl -X POST http://localhost:11434/api/chat \ -H Content-Type: application/json \ -d { model: phi3:mini, messages: [ {role: user, content: 你好} ] } # 应返回包含message.content的JSON # 4. 在前端封装AI调用 // src/api/ai.ts export const callPhi3 async (prompt: string): Promisestring { const res await fetch(http://localhost:11434/api/chat, { method: POST, headers: { Content-Type: application/json }, body: JSON.stringify({ model: phi3:mini, messages: [{ role: user, content: prompt }] }) }); if (!res.ok) throw new Error(AI调用失败); const data await res.json(); return data.message.content; };注意Ollama默认只监听localhost若Tauri前端在WebView里调用需确认localhost解析正确。遇到CORS问题可在Ollama启动时加--host 0.0.0.0:11434并在tauri.conf.json里配置allowlist http scope允许跨域。4.6 步骤6实现信号交叉验证逻辑12分钟创建src/utils/aiValidation.tsimport { Signal } from ../types/strategy; import { callPhi3 } from ../api/ai; interface ValidationResult { final_decision: buy | sell | hold | hold_for_review; rationale: string; confidence_adjusted: number; } export const validateSignals async ( signals: Signal[] ): PromiseValidationResult[] { // 构建Prompt取Top 10信号拼接成一段文本 const top10 signals.slice(0, 10).map(s 股票${s.symbol}策略${s.strategy_id}置信度${(s.confidence_score * 100).toFixed(0)}%风险等级${s.risk_level}/10理由${s.reasoning_summary} ).join(\n); const prompt 你是一名资深A股量化研究员正在审核以下交易信号。请严格按步骤执行 1. 检查逻辑自洽性如动量策略推荐买入其涨幅是否真高 2. 检查信号冲突同一股票多策略推荐相反操作 3. 检查风险匹配低置信高风险需标记 4. 输出JSON{final_decision: ..., rationale: ..., confidence_adjusted: 0.0~1.0} 信号列表 ${top10} ; try { const response await callPhi3(prompt); // 解析Phi-3-mini返回的JSON字符串它有时会带多余文字 const jsonStart response.indexOf({); const jsonEnd response.lastIndexOf(}) 1; const jsonStr response.slice(jsonStart, jsonEnd); return JSON.parse(jsonStr) as ValidationResult[]; } catch (err) { console.error(AI验证失败, err); // 降级返回原信号不调整 return signals.map(s ({ final_decision: s.signal_type as any, rationale: AI验证服务不可用采用原始信号, confidence_adjusted: s.confidence_score })); } };这个函数把10个信号压缩成一段Prompt交给Phi-3-mini处理。实测发现Phi-3-mini对长Prompt的JSON输出稳定性不如短Prompt所以限制为Top 10既保证信息量又控制误差率。4.7 步骤7构建K线图表组件20分钟用recharts库轻量、TS友好npm install rechartssrc/components/KLineChart.tsximport React from react; import { LineChart, Line, XAxis, YAxis, CartesianGrid, Tooltip, Legend, ResponsiveContainer } from recharts; interface KLineData { time: number; open: number; high: number; low: number; close: number; volume: number; } interface KLineProps { data: KLineData[]; symbol: string; } const KLineChart ({ data, symbol }: KLineProps) { // 将Unix时间戳转为日期字符串用于X轴显示 const formattedData data.map(item ({ ...item, date: new Date(item.time).toLocaleTimeString([], { hour: 2-digit, minute: 2-digit }) })); return ( div classNameh-80 h3 classNamefont-medium mb-2{symbol} 分钟级K线/h3 ResponsiveContainer width100% height100% LineChart data{formattedData} CartesianGrid strokeDasharray3 3 / XAxis dataKeydate / YAxis domain{[dataMin - 1, dataMax 1]} / Tooltip formatter{(value) [¥${Number(value).toFixed(2)}, 价格]} labelFormatter{(label) 时间: ${label}} / Legend / Line typemonotone dataKeyclose name收盘价 stroke#3b82f6 activeDot{{ r: 8 }} / Line typemonotone dataKeyopen name开盘价 stroke#10b981 dot{false} / /LineChart /ResponsiveContainer /div ); }; export default KLineChart;关键点YAxis的domain设为[dataMin - 1, dataMax 1]避免价格紧贴坐标轴边缘Tooltip的formatter定制显示格式让数字带¥符号和两位小数activeDot高亮当前悬停点提升交互体验。4.8 步骤8添加券商API对接骨架10分钟QuantBot支持华泰、中信、国泰君安等主流券商。以华泰为例用其htsdkSDK# 在backend/strategy/venv中安装 pip install htsdkbackend/strategy/trade_service.pyfrom htsdk import HTSDK class TradeService: def __init__(self, account: str, password: str, trade_ip: str): self.sdk HTSDK(account, password, trade_ip) def place_order(self, symbol: str, order_type: str, price: float, quantity: int): # order_type: buy or sell # 实际调用htsdk.place_order(...) return {order_id: HT20240520001, status: success} # 在main.py中注入 trade_service TradeService( accountos.getenv(HT_ACCOUNT), passwordos.getenv(HT_PASSWORD), trade_ipos.getenv(HT_TRADE_IP) ) app.post(/api/trade/place) def place_order(request: OrderRequest): result trade_service.place_order( symbolrequest.symbol, order_typerequest.order_type, pricerequest.price, quantityrequest.quantity ) return result前端调用时需在.env里配置VITE_HT_ACCOUNT

关于恒美微站

恒美微站专注于为个体商户、工作室提供极简自助建站服务,让每个人都能轻松拥有专业网站。

快速链接

  • 关于我们
  • 建站服务
  • 主题模板
  • 案例展示
  • 资讯中心

服务项目

  • 可视化建站
  • 拖拽编辑
  • 主题定制
  • SEO 优化
  • 网站托管

联系方式

  • 📍 地址:北京市朝阳区建国路 88 号
  • 📞 电话:400-888-8888
  • ✉️ 邮箱:info@hmyw.cn
  • 🕐 时间:周一至周日 9:00-18:00

© 2024 恒美微站 hmyw.cn 版权所有 | 京 ICP 备 12345678 号