Phân tích

@tradecanvas/analytics cung cấp một bộ backtest chiến lược headless, chạy từng nến một, kèm theo dõi danh mục và bộ tính tổng hợp chỉ số rủi ro. Kết hợp với chế độ phát lại để hiển thị các giao dịch trên biểu đồ.

Backtest trực tiếp — giao cắt SMA(10/30)

365 ngày dữ liệu giá tổng hợp, vốn ban đầu $10k, phí 0,05%, trượt giá 0,03%.

Đang chạy backtest…

↑ Backtest giao cắt SMA(10/30) chạy trực tiếp trên 365 ngày dữ liệu tổng hợp tất định. Kéo thanh trượt hoặc bấm Phát để đi qua đường vốn từng nến một.

Backtester

Mô hình khớp lệnh:

  • Hàm chiến lược chạy khi mỗi nến đóng cửa.
  • Lệnh đặt ở nến N được khớp ở nến N+1 — lệnh thị trường khớp tại giá mở cửa; lệnh limit/stop khớp khi nến giao dịch xuyên qua giá kích hoạt.
  • Vốn (equity) được định giá theo giá đóng cửa của mỗi nến.
import { Backtester, FixedCommission, PercentSlippage } from '@tradecanvas/analytics'

const bt = new Backtester({
  initialCash: 10_000,
  commission: new FixedCommission(2),
  slippage: new PercentSlippage(0.0005),
  allowShort: true,
})

const result = bt.run(historicalBars, (ctx) => {
  if (!ctx.position) {
    ctx.placeOrder({ side: 'long', type: 'market', quantity: 1 })
  } else if (ctx.bar.close > ctx.position.averagePrice * 1.02) {
    ctx.close()
  }
})

console.log(result.metrics.sharpe, result.metrics.maxDrawdownPct)

StrategyContext

Trường / phương thứcMô tả
barNến hiện tại.
indexChỉ số của bar trong chuỗi đầu vào.
historyCác nến tính đến và bao gồm bar.
positionVị thế hiện tại hoặc null.
cashTiền mặt khả dụng.
equityTiền mặt + giá trị vị thế theo giá thị trường.
placeOrder(order)Xếp lệnh vào hàng đợi cho nến tiếp theo.
close(tag?)Đóng vị thế hiện tại bằng lệnh thị trường.
cancel(orderId)Huỷ một lệnh đang chờ.

Mô hình phí & trượt giá

  • FixedCommission(perTrade)
  • PercentCommission(rate) — tỉ lệ trên giá trị danh nghĩa, ví dụ 0.001 = 10 bps.
  • PerShareCommission(perShare, minimum?)
  • PercentSlippage(rate) — tỉ lệ bất lợi trên giá.
  • RangeBasedSlippage(factor) — tỉ lệ với biên độ của nến.

Portfolio

Theo dõi tiền mặt, một vị thế ròng, lãi/lỗ đã chốt (P&L) và đường vốn.

const portfolio = new Portfolio({ initialCash: 10_000 })
portfolio.applyFill({ ... })
portfolio.mark(time, price)         // record equity point

portfolio.getPosition()             // → { side, quantity, averagePrice, ... } | null
portfolio.getTrades()               // → closed trades
portfolio.getEquityCurve()          // → equity points
portfolio.equity(price)             // mark-to-market

Chỉ số rủi ro

import { computeRiskMetrics } from '@tradecanvas/analytics'

const m = computeRiskMetrics(initialCash, equityCurve, trades, {
  periodsPerYear: 252,    // optional; auto-detected from timestamps
  riskFreeRate: 0.03,
})

m.totalReturnPct
m.cagr
m.sharpe
m.sortino
m.calmar
m.maxDrawdownPct
m.winRate
m.profitFactor
m.expectancy

Kết hợp equityCurve trong kết quả với EquityCurveRenderer để trực quan hoá kết quả backtest.

Thư viện chiến lược

Các chiến lược mẫu dùng ngay — mỗi hàm trả về một StrategyFn:

import {
  Backtester,
  smaCrossStrategy,
  rsiReversionStrategy,
  donchianBreakoutStrategy,
  bollingerReversionStrategy,
} from '@tradecanvas/analytics'

const bt = new Backtester({ initialCash: 10_000 })
bt.run(bars, smaCrossStrategy({ fastPeriod: 10, slowPeriod: 30 }))

Monte Carlo

Xáo trộn thứ tự các giao dịch đã thực hiện N lần để thấy kết quả phụ thuộc vào trình tự đến mức nào. Một lợi thế vững chắc giữ dải P5/P95 hẹp; một chiến lược dựa vào trình tự may mắn sẽ xoè rộng.

import { runMonteCarlo } from '@tradecanvas/analytics'

const result = bt.run(bars, smaCrossStrategy())
const mc = runMonteCarlo(10_000, result.trades, {
  simulations: 1000,
  seed: 42,  // deterministic
})

mc.equityBands         // per-step P5/P25/P50/P75/P95
mc.finalEquityPercentiles  // { p5, p25, p50, p75, p95 }
mc.probabilityProfitable
mc.worstMaxDrawdownPct