| name | vnpy |
| description | vn.py — open-source quantitative trading framework supporting CTA, spread, options strategies with 20+ broker gateways for Chinese and international markets. |
| homepage | https://www.vnpy.com |
vn.py (Open-Source Quantitative Trading Framework)
vn.py is the most popular open-source quantitative trading framework in China, community-driven. Supports CTA strategies, spread trading, options volatility trading, and more. Connects to CTP, Femas, Hundsun, and 20+ broker gateways.
Docs: https://www.vnpy.com/docs/cn/
GitHub: https://github.com/vnpy/vnpy
Installation
pip install vnpy
pip install vnpy-ctp
pip install vnpy-ctastrategy
pip install vnpy-spreadtrading
pip install vnpy-datamanager
pip install vnpy-sqlite
pip install vnpy-rqdata
Architecture Overview
VeighNa Trader (GUI)
├── Gateway (Broker Interface)
│ ├── CTP (Futures)
│ ├── Femas (Futures)
│ ├── Hundsun UFT (Securities)
│ ├── EMT (Securities)
│ └── IB / Alpaca (International)
├── App (Application Modules)
│ ├── CtaStrategy (CTA Strategy)
│ ├── SpreadTrading (Spread Trading)
│ ├── OptionMaster (Options Trading)
│ ├── PortfolioStrategy (Portfolio Strategy)
│ └── AlgoTrading (Algorithmic Trading)
└── DataService
├── RQData
├── TuShare
└── Custom Data Sources
Launch GUI
from vnpy.event import EventEngine
from vnpy.trader.engine import MainEngine
from vnpy.trader.ui import MainWindow, create_qapp
from vnpy_ctp import CtpGateway
from vnpy_ctastrategy import CtaStrategyApp
from vnpy_spreadtrading import SpreadTradingApp
from vnpy_datamanager import DataManagerApp
qapp = create_qapp()
event_engine = EventEngine()
main_engine = MainEngine(event_engine)
main_engine.add_gateway(CtpGateway)
main_engine.add_app(CtaStrategyApp)
main_engine.add_app(SpreadTradingApp)
main_engine.add_app(DataManagerApp)
main_window = MainWindow(main_engine, event_engine)
main_window.showMaximized()
qapp.exec()
CTA Strategy Development
CTA (Commodity Trading Advisor) strategies are the core strategy type in vn.py, suitable for trend following, mean reversion, etc.
Strategy Template
from vnpy_ctastrategy import (
CtaTemplate,
StopOrder,
TickData,
BarData,
TradeData,
OrderData,
BarGenerator,
ArrayManager,
)
class DoubleMaStrategy(CtaTemplate):
"""Dual Moving Average CTA Strategy"""
author = "Quant Developer"
fast_window = 10
slow_window = 20
fixed_size = 1
fast_ma0 = 0.0
slow_ma0 = 0.0
parameters = ["fast_window", "slow_window", "fixed_size"]
variables = ["fast_ma0", "slow_ma0"]
def __init__(self, cta_engine, strategy_name, vt_symbol, setting):
super().__init__(cta_engine, strategy_name, vt_symbol, setting)
self.bg = BarGenerator(self.on_bar)
self.am = ArrayManager(size=100)
def on_init(self):
"""Strategy initialization — load historical data"""
self.write_log()
.load_bar()
():
.write_log()
():
.write_log()
():
.bg.update_tick(tick)
():
.am.update_bar(bar)
.am.inited:
fast_ma = .am.sma(.fast_window, array=)
slow_ma = .am.sma(.slow_window, array=)
cross_over = fast_ma > slow_ma
cross_below = fast_ma < slow_ma
cross_over:
.pos == :
.buy(bar.close_price, .fixed_size)
.pos < :
.cover(bar.close_price, (.pos))
.buy(bar.close_price, .fixed_size)
cross_below:
.pos == :
.short(bar.close_price, .fixed_size)
.pos > :
.sell(bar.close_price, (.pos))
.short(bar.close_price, .fixed_size)
.fast_ma0 = fast_ma
.slow_ma0 = slow_ma
.put_event()
():
():
.put_event()
():
Trading Functions Reference
| Method | Description |
|---|
self.buy(price, volume) | Buy to open long position |
self.sell(price, volume) | Sell to close long position |
self.short(price, volume) | Sell to open short position |
self.cover(price, volume) | Buy to close short position |
self.cancel_all() | Cancel all pending orders |
self.write_log(msg) | Write log message |
self.put_event() | Trigger GUI update |
self.load_bar(days) | Load N days of historical bars |
self.load_tick(days) | Load N days of historical ticks |
ArrayManager Indicator Methods
The ArrayManager provides built-in technical indicator calculations:
am = ArrayManager(size=100)
am.sma(n, array=False)
am.ema(n, array=False)
am.kama(n, array=False)
am.std(n, array=False)
am.atr(n, array=False)
am.rsi(n, array=False)
am.cci(n, array=False)
am.macd(fast, slow, signal)
am.adx(n, array=False)
am.boll(n, dev, array=False)
am.donchian(n, array=False)
am.aroon(n, array=False)
am.trix(n, array=False)
BarGenerator — Multi-Timeframe Bars
from vnpy_ctastrategy import BarGenerator
class MyStrategy(CtaTemplate):
def __init__(self, cta_engine, strategy_name, vt_symbol, setting):
super().__init__(cta_engine, strategy_name, vt_symbol, setting)
self.bg = BarGenerator(self.on_bar, 15, self.on_15min_bar)
self.am = ArrayManager()
def on_tick(self, tick: TickData):
self.bg.update_tick(tick)
def on_bar(self, bar: BarData):
"""1-minute bar callback — feed into 15-min generator"""
self.bg.update_bar(bar)
def on_15min_bar(self, bar: BarData):
"""15-minute bar callback — main trading logic"""
self.am.update_bar(bar)
if not self.am.inited:
return
Supported intervals for BarGenerator:
- Minutes: 1, 3, 5, 15, 30, 60
- Hours: pass
Interval.HOUR as the interval parameter
- Custom: any integer N for N-minute bars
Spread Trading
from vnpy_spreadtrading import (
SpreadStrategyTemplate,
SpreadAlgoTemplate,
SpreadData,
LegData,
BacktestingEngine,
)
class SpreadArbitrageStrategy(SpreadStrategyTemplate):
"""Simple spread arbitrage strategy"""
author = "Quant Developer"
buy_price = 0.0
sell_price = 0.0
max_pos = 10
payup = 10
parameters = ["buy_price", "sell_price", "max_pos", "payup"]
def on_init(self):
self.write_log("Strategy initializing")
def on_start(self):
self.write_log("Strategy started")
def on_spread_data(self):
"""Spread data update callback"""
spread = self.get_spread_tick()
if not spread:
return
if self.spread_pos < self.max_pos:
if spread.last_price <= self.buy_price:
self.start_long_algo(
spread.last_price, self.max_pos - self.spread_pos,
payup=self.payup
)
if .spread_pos > -.max_pos:
spread.last_price >= .sell_price:
.start_short_algo(
spread.last_price, .max_pos + .spread_pos,
payup=.payup
)
Live Trading Setup
from vnpy.event import EventEngine
from vnpy.trader.engine import MainEngine
from vnpy_ctp import CtpGateway
from vnpy_ctastrategy import CtaStrategyApp
event_engine = EventEngine()
main_engine = MainEngine(event_engine)
main_engine.add_gateway(CtpGateway)
cta_engine = main_engine.add_app(CtaStrategyApp)
ctp_setting = {
"userid": "your_user_id",
"password": "your_password",
"brokerid": "9999",
"td_address": "tcp://180.168.146.187:10201",
"md_address": "tcp://180.168.146.187:10211",
"appid": "simnow_client_test",
"auth_code": "0000000000000000",
}
main_engine.connect(ctp_setting, "CTP")
cta_engine.init_engine()
cta_engine.add_strategy(
DoubleMaStrategy,
"double_ma_IF",
"IF2401.CFFEX",
{"fast_window": 10, "slow_window": 20}
)
cta_engine.init_strategy("double_ma_IF")
cta_engine.start_strategy("double_ma_IF")
Data Management
from vnpy_datamanager import DataManagerApp
dm_engine = main_engine.add_app(DataManagerApp)
dm_engine.download_bar_data(
symbol="IF2401",
exchange="CFFEX",
interval="1m",
start=datetime(2024, 1, 1)
)
Advanced Examples
RSI Mean Reversion Strategy
from vnpy_ctastrategy import CtaTemplate, BarData, BarGenerator, ArrayManager
class RsiStrategy(CtaTemplate):
"""RSI mean reversion strategy — buy oversold, sell overbought"""
author = "Quant Developer"
rsi_period = 14
rsi_buy = 30
rsi_sell = 70
fixed_size = 1
parameters = ["rsi_period", "rsi_buy", "rsi_sell", "fixed_size"]
variables = ["rsi_value"]
rsi_value = 0.0
def __init__(self, cta_engine, strategy_name, vt_symbol, setting):
super().__init__(cta_engine, strategy_name, vt_symbol, setting)
self.bg = BarGenerator(self.on_bar, 15, self.on_15min_bar)
self.am = ArrayManager()
def on_init(self):
self.write_log("Strategy initializing")
self.load_bar(10)
def on_start(self):
self.write_log("Strategy started")
def on_stop(self):
self.write_log()
():
.bg.update_tick(tick)
():
.bg.update_bar(bar)
():
.am.update_bar(bar)
.am.inited:
.rsi_value = .am.rsi(.rsi_period)
.pos == :
.rsi_value < .rsi_buy:
.buy(bar.close_price, .fixed_size)
.rsi_value > .rsi_sell:
.short(bar.close_price, .fixed_size)
.pos > :
.rsi_value > .rsi_sell:
.sell(bar.close_price, (.pos))
.short(bar.close_price, .fixed_size)
.pos < :
.rsi_value < .rsi_buy:
.cover(bar.close_price, (.pos))
.buy(bar.close_price, .fixed_size)
.put_event()
():
():
.put_event()
():
Bollinger Band Breakout Strategy
from vnpy_ctastrategy import CtaTemplate, BarData, BarGenerator, ArrayManager
class BollBreakoutStrategy(CtaTemplate):
"""Bollinger Band breakout strategy with ATR-based stop loss"""
author = "Quant Developer"
boll_period = 20
boll_dev = 2.0
atr_period = 14
atr_multiplier = 2.0
fixed_size = 1
parameters = ["boll_period", "boll_dev", "atr_period", "atr_multiplier", "fixed_size"]
variables = ["boll_up", "boll_down", "atr_value"]
boll_up = 0.0
boll_down = 0.0
atr_value = 0.0
def __init__(self, cta_engine, strategy_name, vt_symbol, setting):
super().__init__(cta_engine, strategy_name, vt_symbol, setting)
self.bg = BarGenerator(self.on_bar, 30, self.on_30min_bar)
self.am = ArrayManager()
def on_init(self):
self.write_log("Strategy initializing")
self.load_bar(10)
def on_start(self):
self.write_log("Strategy started")
():
.write_log()
():
.bg.update_tick(tick)
():
.bg.update_bar(bar)
():
.cancel_all()
.am.update_bar(bar)
.am.inited:
.boll_up, .boll_down = .am.boll(.boll_period, .boll_dev)
.atr_value = .am.atr(.atr_period)
.pos == :
bar.close_price > .boll_up:
.buy(bar.close_price, .fixed_size)
bar.close_price < .boll_down:
.short(bar.close_price, .fixed_size)
.pos > :
stop_price = bar.close_price - .atr_value * .atr_multiplier
.sell(stop_price, (.pos), stop=)
.pos < :
stop_price = bar.close_price + .atr_value * .atr_multiplier
.cover(stop_price, (.pos), stop=)
.put_event()
():
():
.put_event()
():
Supported Gateways
| Gateway | Market | Protocol |
|---|
| CTP | China Futures | CTP |
| Femas | China Futures | Femas |
| Hundsun UFT | China Securities | UFT |
| EMT | China Securities | EMT |
| XTP | China Securities | XTP |
| IB | International | TWS API |
| Alpaca | US Stocks | REST API |
| Binance | Crypto | REST/WebSocket |
Tips
- vn.py is the go-to framework for live trading in Chinese futures and securities markets.
- Use
BarGenerator to synthesize multi-timeframe bars from tick data.
ArrayManager provides 20+ built-in technical indicators — no need for external libraries.
- For backtesting, use the built-in
BacktestingEngine in vnpy_ctastrategy.
- CTP gateway requires a broker account with CTP access (e.g., SimNow for testing).
- The modular architecture allows mixing gateways and strategy types freely.
- Docs: https://www.vnpy.com/docs/cn/
社区与支持
由 大佬量化 (Boss Quant) 维护 — 量化交易教学与策略研发团队。
微信客服: bossquant1 · Bilibili · 搜索 大佬量化 on 微信公众号 / Bilibili / 抖音