量化交易/股票交易

Posted on:February 1, 2025 at 08:14 AM
预计阅读时长:17 min read 字数:3336

2025,股票交易成神之路

目录

如何用js做量化

以下是使用 JavaScript 构建量化交易系统的分步指南,涵盖核心工具、代码示例和注意事项:


一、JavaScript在量化交易中的适用场景

  • 低频策略:日线/小时级交易,无需微秒级响应。
  • 数据可视化:配合D3.js或Echarts展示策略回测结果。
  • 辅助工具开发:爬虫(数据抓取)、实时监控面板、自动化通知。
  • 加密货币交易:多数交易所(如Binance、Coinbase)提供JS版API。

二、核心工具链

功能推荐工具/库
数据获取Axios(HTTP请求)、Puppeteer(网页爬虫)、交易所WebSocket API
数据处理Pandas-js(类似Python Pandas)、math.js(数学计算)
技术指标Tulip-node(TA-Lib的JS移植)、technicalindicators(MACD/RSI等)
回测框架Backtesting.js(轻量级)、QuantConnect(支持JS的云端平台)
实盘交易交易所官方SDK(如binance-api-node)、ccxt(跨交易所统一接口)
可视化Plotly.jsHighcharts

三、开发步骤与代码示例

1. 数据获取(以Binance为例)

const Binance = require("binance-api-node").default;
const client = Binance();

// 获取比特币历史K线数据
async function fetchData() {
  const candles = await client.candles({
    symbol: "BTCUSDT",
    interval: "1h",
    limit: 100,
  });
  return candles.map(c => ({
    time: new Date(c.openTime),
    open: parseFloat(c.open),
    high: parseFloat(c.high),
    low: parseFloat(c.low),
    close: parseFloat(c.close),
  }));
}

2. 策略开发(双均线策略)

const tulind = require("tulind");

// 计算双均线
async function calculateMA(data) {
  const closes = data.map(d => d.close);
  const [ma5] = await tulind.indicators.sma.indicator([closes], [5]);
  const [ma20] = await tulind.indicators.sma.indicator([closes], [20]);
  return { ma5, ma20 };
}

// 生成交易信号
function generateSignals(data, ma5, ma20) {
  let signals = [];
  for (let i = 20; i < data.length; i++) {
    // 确保足够数据计算MA20
    if (ma5[i - 1] < ma20[i - 1] && ma5[i] > ma20[i]) {
      signals.push({ time: data[i].time, action: "buy" });
    } else if (ma5[i - 1] > ma20[i - 1] && ma5[i] < ma20[i]) {
      signals.push({ time: data[i].time, action: "sell" });
    }
  }
  return signals;
}

3. 回测引擎(简化版)

function backtest(data, signals) {
  let portfolio = { cash: 10000, btc: 0, trades: [] };

  signals.forEach(signal => {
    const price = data.find(d => d.time === signal.time).close;
    if (signal.action === "buy" && portfolio.cash > 0) {
      portfolio.btc = portfolio.cash / price;
      portfolio.cash = 0;
      portfolio.trades.push({ ...signal, price });
    } else if (signal.action === "sell" && portfolio.btc > 0) {
      portfolio.cash = portfolio.btc * price;
      portfolio.btc = 0;
      portfolio.trades.push({ ...signal, price });
    }
  });

  return portfolio;
}

4. 可视化结果(使用Plotly.js)

const plotly = require("plotly")("username", "api-key");

function plotResults(data, ma5, ma20) {
  const tracePrice = {
    x: data.map(d => d.time),
    close: data.map(d => d.close),
    type: "candlestick",
    name: "BTC/USDT",
  };

  const traceMA5 = {
    x: data.slice(4).map(d => d.time), // MA5从第5个数据点开始
    y: ma5,
    type: "scatter",
    name: "MA5",
  };

  const traceMA20 = {
    x: data.slice(19).map(d => d.time), // MA20从第20个数据点开始
    y: ma20,
    type: "scatter",
    name: "MA20",
  };

  const layout = { title: "双均线策略回测" };
  plotly.plot([tracePrice, traceMA5, traceMA20], layout);
}

四、实盘部署(以Binance为例)

const ccxt = require("ccxt");
const binance = new ccxt.binance({
  apiKey: "YOUR_API_KEY",
  secret: "YOUR_SECRET",
});

async function executeTrade(signal) {
  try {
    const symbol = "BTC/USDT";
    const amount = 0.001; // 交易数量
    const order = await binance.createOrder(
      symbol,
      "market",
      signal.action,
      amount
    );
    console.log("订单成交:", order);
  } catch (error) {
    console.error("交易失败:", error);
  }
}

五、注意事项

  1. 性能瓶颈
    • JS单线程特性不适合高频交易,可用WebAssembly加速计算(如Rust编写核心算法)。
  2. 数据清洗
    • 处理缺失值:data = data.filter(d => d.open && d.high && d.low && d.close);
  3. 风险控制
    • 添加止损逻辑:
      let stopLossPrice = entryPrice * 0.95; // 5%止损
      if (currentPrice < stopLossPrice) forceSell();
      

六、学习资源

  • 书籍
    • 《JavaScript for Quantitative Finance》
  • 开源项目
  • 课程
    • Udemy《Algorithmic Trading with JavaScript》

总结

JavaScript适合低频策略原型开发全栈量化系统构建(前端展示+后端逻辑),但在复杂数学运算和高频场景中需谨慎。建议先用JS验证策略逻辑,再针对性能关键模块换用Python/C++。

cursor问题构建

  • 直接将图表渲染到dom中,能交互,使用vue服务端组件,实现自己选择时间区间,选择时间后相应地请求数据,参数为start_date,起始日期。格式“yyyy-mm-dd”,和end_date,格式同start_date
examples/quantitative/toImage.js
1import { createSSRApp } from 'vue' 2import axios from 'axios'; 3import Chart from 'chart.js/auto'; 4import { createCanvas, loadImage } from 'canvas'; 5import express from 'express'; 6import { createApp } from 'vue'; 7import { renderToString } from 'vue/server-renderer'; 8const app = express(); 9const port = 3000; 10 11// 获取股票历史数据 12async function getStockData(stockCode) { 13 const url = `https://tsanghi.com/api/fin/stock/XSHG/daily?token=55969acdb0134b2eba8bb47dd40c47f7&ticker=${stockCode}`; 14 const response = await axios.get(url); 15 return response.data.data; 16} 17 18// 使用Chart.js可视化数据 19function visualizeData(data, startDate, endDate) { 20 const filteredData = data.filter(item => { 21 const date = new Date(item.date); 22 return date >= new Date(startDate) && date <= new Date(endDate); 23 }); 24 const dates = filteredData.map(item => item.date); 25 const closes = filteredData.map(item => item.close); 26 27 // 创建canvas 28 const canvas = createCanvas(800, 400); 29 const ctx = canvas.getContext('2d'); 30 31 // 绘制图表 32 new Chart(ctx, { 33 type: 'line', 34 data: { 35 labels: dates, 36 datasets: [{ 37 label: '收盘价', 38 data: closes, 39 borderColor: 'rgba(75, 192, 192, 1)', 40 fill: false 41 }] 42 }, 43 options: { 44 responsive: false, 45 scales: { 46 x: { 47 title: { 48 display: true, 49 text: '日期' 50 } 51 }, 52 y: { 53 title: { 54 display: true, 55 text: '价格' 56 } 57 } 58 } 59 } 60 }); 61 62 return canvas; 63} 64 65const StockChart = { 66 template: ` 67 <div> 68 <div> 69 <label>起始日期:</label> 70 <input type="date" v-model="startDate" /> 71 <label>结束日期:</label> 72 <input type="date" v-model="endDate" /> 73 <button @click="fetchData">更新图表</button> 74 </div> 75 <canvas ref="chartCanvas" style="width:100%;height:500px;"></canvas> 76 </div> 77 `, 78 data() { 79 return { 80 stockCode: '600519', 81 startDate: '2023-01-01', 82 endDate: '2023-12-31', 83 chartInstance: null 84 }; 85 }, 86 async mounted() { 87 await this.fetchData(); 88 }, 89 methods: { 90 async fetchData() { 91 try { 92 const stockData = await getStockData(this.stockCode); 93 const canvas = visualizeData(stockData, this.startDate, this.endDate); 94 95 // 更新DOM中的canvas 96 const ctx = this.$refs.chartCanvas.getContext('2d'); 97 this.$refs.chartCanvas.width = canvas.width; 98 this.$refs.chartCanvas.height = canvas.height; 99 ctx.drawImage(canvas, 0, 0); 100 } catch (error) { 101 console.error('获取数据失败:', error); 102 } 103 } 104 } 105}; 106 107// 修改 express 路由 108app.get('/', async (req, res) => { 109 const app = createSSRApp(StockChart); 110 111 try { 112 const html = await renderToString(app); 113 res.end(` 114 <!DOCTYPE html> 115 <html lang="en"> 116 <head> 117 <meta charset="UTF-8"> 118 <title>股票图表</title> 119 </head> 120 <body> 121 <div id="app">${html}</div> 122 <script src="https://unpkg.com/vue@3/dist/vue.global.js"></script> 123 <script> 124 const { createApp } = Vue; 125 const app = createApp(${JSON.stringify(StockChart)}); 126 // 确保在客户端挂载时触发mounted 127 app.mount('#app', true); // 添加true参数强制水合 128 </script> 129 </body> 130 </html> 131 `); 132 } catch (err) { 133 res.status(500).end('Internal Server Error'); 134 } 135}); 136 137// 修改main函数 138app.listen(port, () => { 139 console.log(`服务已启动,访问 http://localhost:${port}/chart?stockCode=600519&startDate=2023-01-01&endDate=2023-12-31`); 140}); 141

优化方案,使用nextjs吧

两个交易策略的实现和原理:

SMA (简单移动平均线) 策略

case 'sma': {
  if (slicedData.length < period + 1) return null;

  const prices = slicedData.map(candle => candle.close);
  const sma = indicators.sma(prices, period);
  const currentPrice = prices[prices.length - 1];
  const currentSMA = sma[sma.length - 1];
  const previousPrice = prices[prices.length - 2];
  const previousSMA = sma[sma.length - 2];

  // 价格从下方穿过 SMA,买入信号
  if (previousPrice < previousSMA && currentPrice > currentSMA) {
    return 'buy';
  }
  // 价格从上方穿过 SMA,卖出信号
  if (previousPrice > previousSMA && currentPrice < currentSMA) {
    return 'sell';
  }
  return null;
}

SMA策略原理: 计算指定周期(如20天)的移动平均线 当价格从下方突破均线时(金叉),产生买入信号 当价格从上方跌破均线时(死叉),产生卖出信号 这个策略适合趋势型行情,在震荡市可能会产生虚假信号

RSI (相对强弱指标) 策略:

case 'rsi': {
  if (slicedData.length < period + 1) return null;

  const prices = slicedData.map(candle => candle.close);
  const rsiValues = indicators.rsi(prices, period);
  const currentRSI = rsiValues[rsiValues.length - 1];

  // RSI < 30 超卖,买入信号
  if (currentRSI < 30) return 'buy';
  // RSI > 70 超买,卖出信号
  if (currentRSI > 70) return 'sell';
  return null;
}

RSI策略原理: RSI衡量价格的超买超卖状态,取值范围0-100 RSI < 30被认为是超卖区域,可能会反弹,产生买入信号 RSI > 70被认为是超买区域,可能会回落,产生卖出信号 这个策略适合震荡行情,在单边趋势市场可能会造成较大损失

RSI的计算过程(在indicators.js中实现)

rsi: function(data, period = 14) {
  const changes = [];
  const gains = [];
  const losses = [];

  // 1. 计算价格变化
  for(let i = 1; i < data.length; i++) {
    changes[i] = data[i] - data[i-1];
    gains[i] = changes[i] > 0 ? changes[i] : 0;
    losses[i] = changes[i] < 0 ? -changes[i] : 0;
  }

  // 2. 计算首个RSI值
  let avgGain = gains.slice(1, period + 1).reduce((sum, gain) => sum + gain, 0) / period;
  let avgLoss = losses.slice(1, period + 1).reduce((sum, loss) => sum + loss, 0) / period;

  // 3. 使用平滑移动平均计算后续RSI值
  const result = Array(period).fill(null);
  for(let i = period; i < data.length; i++) {
    avgGain = ((avgGain * (period - 1)) + gains[i]) / period;
    avgLoss = ((avgLoss * (period - 1)) + losses[i]) / period;

    const RS = avgGain / avgLoss;
    result.push(100 - (100 / (1 + RS)));
  }

  return result;
}

策略使用建议: SMA策略: 适合中长期趋势交易 建议在较大的时间周期上使用(如日线、周线) 可以使用多个周期的均线组合(如金叉死叉) 建议在趋势明确的市场中使用 RSI策略: 适合短期交易和震荡市场 建议配合其他指标使用(如MACD) 可以根据市场情况调整超买超卖阈值 在强趋势市场中要谨慎使用

这两个策略都是比较基础的技术分析策略,建议: 可以组合使用多个指标 添加止损止盈条件 考虑加入趋势过滤器 根据不同市场情况动态调整参数

《主动投资组合管理》

核心内容总结

《主动投资管理》核心内容总结


一、主动投资的基本概念

  1. 定义与目标

    • 主动投资旨在通过分析、预测和策略调整,超越市场基准(如指数收益),追求超额收益(Alpha)。
    • 核心理念:市场并非完全有效,存在定价错误的机会。
  2. 与被动投资的对比

    • 主动管理:依赖基金经理的决策能力,费用较高,风险与收益波动性大。
    • 被动管理:跟踪指数,费用低,收益贴近市场平均水平。
    • 关键分歧:市场有效性假说(EMH)的接受程度。

二、主动投资的核心策略

  1. 选股策略

    • 价值投资:寻找被低估的股票(低P/E、P/B),关注企业基本面。
    • 成长投资:押注高增长潜力的公司(高营收增速、创新技术)。
    • 质量因子:筛选盈利稳定、负债低、管理优秀的公司。
  2. 择时与资产配置

    • 根据宏观经济周期调整股债比例(如美林时钟理论)。
    • 利用技术分析(趋势、动量)或事件驱动(政策变化、财报季)捕捉短期机会。
  3. 多空策略与对冲

    • 通过做多低估资产、做空高估资产,对冲系统性风险。
    • 案例:对冲基金的股票多空组合、市场中性策略。

三、超额收益(Alpha)的来源

  1. 信息优势

    • 深度研究(行业调研、非公开数据)获取独家洞见。
    • 行为金融学视角:利用市场参与者的认知偏差(如过度反应、羊群效应)。
  2. 风险溢价与因子暴露

    • 系统性暴露于特定风险因子(如小盘股、低波动率、高股息),获取长期溢价。
    • Fama-French三因子模型:市场风险、市值因子、价值因子。
  3. 动态调整能力

    • 灵活应对市场变化(如黑天鹅事件),调整仓位或策略。

四、风险管理与绩效评估

  1. 主动风险(跟踪误差)

    • 定义:投资组合收益与基准收益的波动差异。
    • 管理目标:在可控风险下最大化Alpha。
  2. 关键指标

    • 信息比率(IR):超额收益与跟踪误差的比值,衡量单位风险下的Alpha获取效率。
    • 夏普比率:组合收益与总风险的比值,评估风险调整后收益。
  3. 回撤控制

    • 设定止损线、分散投资(跨资产、跨行业)、压力测试。

五、主动投资的挑战与局限

  1. 市场有效性提升

    • 信息透明度增加、算法交易普及,导致定价错误机会减少。
  2. 成本压力

    • 高管理费、交易成本侵蚀收益,长期跑赢指数难度大。
  3. 行为偏差干扰

    • 过度自信、损失厌恶等心理因素可能导致非理性决策。
  4. 规模瓶颈

    • 管理规模扩大后,策略灵活性下降(如小盘股策略容量有限)。

六、成功主动管理的关键要素

  1. 清晰的竞争优势

    • 独特的数据源、研究能力或执行速度。
  2. 纪律性与一致性

    • 避免频繁切换策略,坚持长期验证有效的框架。
  3. 持续学习与迭代

    • 适应市场结构变化(如ESG投资兴起、量化模型迭代)。
  4. 利益对齐机制

    • 基金经理与投资者利益绑定(如跟投制度、高绩效费门槛)。

七、未来展望

  • 量化与AI的融合:机器学习辅助挖掘非传统数据(社交媒体、卫星图像)。
  • ESG整合:将环境、社会和治理因素纳入主动决策,提升长期可持续性。
  • 主动ETF的崛起:结合主动策略与ETF的低成本、高流动性优势。

总结:主动投资管理是一门科学与艺术的结合,需平衡收益追求与风险控制,依赖深度研究、严格纪律和持续创新。尽管面临市场效率提升的挑战,但通过差异化策略和适应性进化,仍可为投资者创造价值。

公司基本面分析

广联达

让我为您分析一下广联达(股票代码:002410):

  1. 公司基本面

主营业务:

建筑信息化软件和服务的龙头企业

主要产品包括工程造价软件、工程施工软件、BIM软件等

正在向数字建筑平台服务商转型

财务状况:

营收持续增长,2023年前三季度营收44.97亿元,同比增长24.01%

毛利率保持在90%左右,属于高毛利行业

研发投入大,约占营收的20%以上

现金流充裕,财务状况健康

市场地位:

工程造价软件市场份额超过90%

施工领域市场份额约50%

BIM领域处于领先地位

  1. 高管团队

核心高管:

董事长刁志中:公司创始人,持股19.89%,为第一大股东

总裁袁正刚:从业20多年,对建筑行业理解深刻

副总裁王爱华:负责财务工作,具有丰富的财务管理经验

高管特点:

管理团队稳定,大多具有多年行业经验

持股激励计划完善,高管利益与公司发展深度绑定

研发背景强,重视技术创新

  1. 发展优势

行业壁垒高,用户黏性强

数据积累优势明显

云转型进展顺利

政策支持(“新基建”、“数字中国”等)

  1. 潜在风险

房地产行业下行可能影响业务发展

新业务拓展不及预期的风险

人力成本上升压力

市场竞争加剧

  1. 未来展望

数字化转型带来新机遇

海外市场具有较大发展空间

新技术(如AI)应用前景广阔

存量市场改造空间大

总体来看,广联达是一家具有护城河的优质科技公司,管理团队稳定且专业,未来发展前景良好,但也需要关注行业环境变化带来的风险。