CTA策略模块
CTA策略模块
CTA策略模块
http://www.vnpy.com/docs/cn/cta_strategy.html#id2 Page 1 of 26
CTA策略略模块 10/2/19, 1(07 AM
def init_rqdata(self):
"""
Init RQData client.
"""
username = SETTINGS["rqdata.username"]
password = SETTINGS["rqdata.password"]
if not username or not password:
return
import rqdatac
self.rq_client = rqdatac
self.rq_client.init(username, password,
('rqdatad-pro.ricequant.com', 16011))
http://www.vnpy.com/docs/cn/cta_strategy.html#id2 Page 2 of 26
CTA策略略模块 10/2/19, 1(07 AM
def query_bar_from_rq(
self, vt_symbol: str, interval: Interval, start: datetime, end:
datetime
):
"""
Query bar data from RQData.
"""
symbol, exchange_str = vt_symbol.split(".")
rq_symbol = to_rq_symbol(vt_symbol)
if rq_symbol not in self.rq_symbols:
return None
df = self.rq_client.get_price(
rq_symbol,
frequency=interval.value,
fields=["open", "high", "low", "close", "volume"],
start_date=start,
end_date=end
)
data = []
for ix, row in df.iterrows():
bar = BarData(
symbol=symbol,
exchange=Exchange(exchange_str),
interval=interval,
datetime=row.name.to_pydatetime(),
open_price=row["open"],
high_price=row["high"],
low_price=row["low"],
close_price=row["close"],
volume=row["volume"],
gateway_name="RQ"
)
data.append(bar)
http://www.vnpy.com/docs/cn/cta_strategy.html#id2 Page 3 of 26
CTA策略略模块 10/2/19, 1(07 AM
boll_window = 18
boll_dev = 3.4
cci_window = 10
atr_window = 30
sl_multiplier = 5.2
fixed_size = 1
boll_up = 0
boll_down = 0
cci_value = 0
atr_value = 0
intra_trade_high = 0
intra_trade_low = 0
long_stop = 0
short_stop = 0
http://www.vnpy.com/docs/cn/cta_strategy.html#id2 Page 4 of 26
CTA策略略模块 10/2/19, 1(07 AM
def on_init(self):
"""
Callback when strategy is inited.
"""
self.write_log(" ")
self.load_bar(10)
def on_start(self):
"""
Callback when strategy is started.
"""
self.write_log(" ")
def on_stop(self):
"""
Callback when strategy is stopped.
"""
self.write_log(" ")
http://www.vnpy.com/docs/cn/cta_strategy.html#id2 Page 5 of 26
CTA策略略模块 10/2/19, 1(07 AM
am = self.am
am.update_bar(bar)
if not am.inited:
return
if self.pos == 0:
self.intra_trade_high = bar.high_price
self.intra_trade_low = bar.low_price
if self.cci_value > 0:
self.buy(self.boll_up, self.fixed_size, True)
elif self.cci_value < 0:
self.short(self.boll_down, self.fixed_size, True)
self.put_event()
http://www.vnpy.com/docs/cn/cta_strategy.html#id2 Page 6 of 26
CTA策略略模块 10/2/19, 1(07 AM
http://www.vnpy.com/docs/cn/cta_strategy.html#id2 Page 7 of 26
CTA策略略模块 10/2/19, 1(07 AM
def load_data(self):
""""""
self.output(" ")
if self.mode == BacktestingMode.BAR:
s = (
DbBarData.select()
.where(
(DbBarData.vt_symbol == self.vt_symbol)
& (DbBarData.interval == self.interval)
& (DbBarData.datetime >= self.start)
& (DbBarData.datetime <= self.end)
)
.order_by(DbBarData.datetime)
)
self.history_data = [db_bar.to_bar() for db_bar in s]
else:
s = (
DbTickData.select()
.where(
(DbTickData.vt_symbol == self.vt_symbol)
& (DbTickData.datetime >= self.start)
& (DbTickData.datetime <= self.end)
)
.order_by(DbTickData.datetime)
)
self.history_data = [db_tick.to_tick() for db_tick in s]
self.output(f" {len(self.history_data)}")
def cross_limit_order(self):
"""
Cross limit order with last bar/tick data.
http://www.vnpy.com/docs/cn/cta_strategy.html#id2 Page 8 of 26
CTA策略略模块 10/2/19, 1(07 AM
"""
if self.mode == BacktestingMode.BAR:
long_cross_price = self.bar.low_price
short_cross_price = self.bar.high_price
long_best_price = self.bar.open_price
short_best_price = self.bar.open_price
else:
long_cross_price = self.tick.ask_price_1
short_cross_price = self.tick.bid_price_1
long_best_price = long_cross_price
short_best_price = short_cross_price
short_cross = (
order.direction == Direction.SHORT
and order.price <= short_cross_price
and short_cross_price > 0
)
self.active_limit_orders.pop(order.vt_orderid)
if long_cross:
trade_price = min(order.price, long_best_price)
pos_change = order.volume
else:
trade_price = max(order.price, short_best_price)
pos_change = -order.volume
trade = TradeData(
symbol=order.symbol,
exchange=order.exchange,
orderid=order.orderid,
tradeid=str(self.trade_count),
direction=order.direction,
offset=order.offset,
price=trade_price,
volume=order.volume,
time=self.datetime.strftime("%H:%M:%S"),
gateway_name=self.gateway_name,
)
trade.datetime = self.datetime
http://www.vnpy.com/docs/cn/cta_strategy.html#id2 Page 9 of 26
CTA策略略模块 10/2/19, 1(07 AM
self.strategy.pos += pos_change
self.strategy.on_trade(trade)
self.trades[trade.vt_tradeid] = trade
def calculate_pnl(
self,
pre_close: float,
start_pos: float,
size: int,
rate: float,
slippage: float,
):
""""""
self.pre_close = pre_close
# Trading pnl is the pnl from new trade during the day
self.trade_count = len(self.trades)
self.trading_pnl += pos_change * \
(self.close_price - trade.price) * size
self.end_pos += pos_change
self.turnover += turnover
self.commission += turnover * rate
self.slippage += trade.volume * size * slippage
http://www.vnpy.com/docs/cn/cta_strategy.html#id2 Page 10 of 26
CTA策略略模块 10/2/19, 1(07 AM
total_days = len(df)
profit_days = len(df[df["net_pnl"] > 0])
loss_days = len(df[df["net_pnl"] < 0])
end_balance = df["balance"].iloc[-1]
max_drawdown = df["drawdown"].min()
max_ddpercent = df["ddpercent"].min()
total_net_pnl = df["net_pnl"].sum()
daily_net_pnl = total_net_pnl / total_days
total_commission = df["commission"].sum()
daily_commission = total_commission / total_days
total_slippage = df["slippage"].sum()
daily_slippage = total_slippage / total_days
total_turnover = df["turnover"].sum()
daily_turnover = total_turnover / total_days
total_trade_count = df["trade_count"].sum()
daily_trade_count = total_trade_count / total_days
if return_std:
sharpe_ratio = daily_return / return_std * np.sqrt(240)
else:
sharpe_ratio = 0
http://www.vnpy.com/docs/cn/cta_strategy.html#id2 Page 11 of 26
CTA策略略模块 10/2/19, 1(07 AM
if df is None:
return
plt.figure(figsize=(10, 16))
balance_plot = plt.subplot(4, 1, 1)
balance_plot.set_title("Balance")
df["balance"].plot(legend=True)
drawdown_plot = plt.subplot(4, 1, 2)
drawdown_plot.set_title("Drawdown")
drawdown_plot.fill_between(range(len(df)), df["drawdown"].value
s)
pnl_plot = plt.subplot(4, 1, 3)
pnl_plot.set_title("Daily Pnl")
df["net_pnl"].plot(kind="bar", legend=False, grid=False, xticks
=[])
distribution_plot = plt.subplot(4, 1, 4)
distribution_plot.set_title("Daily Pnl Distribution")
df["net_pnl"].hist(bins=50)
plt.show()
http://www.vnpy.com/docs/cn/cta_strategy.html#id2 Page 12 of 26
CTA策略略模块 10/2/19, 1(07 AM
engine = BacktestingEngine()
engine.set_parameters(
vt_symbol="IF88.CFFEX",
interval="1m",
start=datetime(2018, 1, 1),
end=datetime(2019, 1, 1),
rate=3.0/10000,
slippage=0.2,
size=300,
pricetick=0.2,
capital=1_000_000,
)
engine.add_strategy(AtrRsiStrategy, {})
engine.load_data()
engine.run_backtesting()
df = engine.calculate_result()
engine.calculate_statistics()
engine.show_chart()
http://www.vnpy.com/docs/cn/cta_strategy.html#id2 Page 13 of 26
CTA策略略模块 10/2/19, 1(07 AM
http://www.vnpy.com/docs/cn/cta_strategy.html#id2 Page 14 of 26
CTA策略略模块 10/2/19, 1(07 AM
df1 = run_backtesting(
strategy_class=AtrRsiStrategy,
setting={},
vt_symbol="IF88.CFFEX",
interval="1m",
start=datetime(2019, 1, 1),
end=datetime(2019, 4, 30),
rate=0.3/10000,
slippage=0.2,
size=300,
pricetick=0.2,
capital=1_000_000,
)
df2 = run_backtesting(
strategy_class=BollChannelStrategy,
setting={'fixed_size': 16},
vt_symbol="RB88.SHFE",
interval="1m",
start=datetime(2019, 1, 1),
end=datetime(2019, 4, 30),
rate=1/10000,
slippage=1,
size=10,
pricetick=1,
capital=1_000_000,
)
def show_portafolio(df):
engine = BacktestingEngine()
engine.calculate_statistics(df)
engine.show_chart(df)
show_portafolio(dfp)
http://www.vnpy.com/docs/cn/cta_strategy.html#id2 Page 15 of 26
CTA策略略模块 10/2/19, 1(07 AM
class OptimizationSetting:
"""
Setting for runnning optimization.
"""
def __init__(self):
""""""
self.params = {}
self.target_name = ""
def add_parameter(
self, name: str, start: float, end: float = None, step: float =
None
):
""""""
if not end and not step:
self.params[name] = [start]
return
if step <= 0:
print(" 0")
return
value = start
value_list = []
self.params[name] = value_list
def generate_setting(self):
""""""
keys = self.params.keys()
values = self.params.values()
products = list(product(*values))
settings = []
for p in products:
setting = dict(zip(keys, p))
settings.append(setting)
return settings
http://www.vnpy.com/docs/cn/cta_strategy.html#id2 Page 16 of 26
CTA策略略模块 10/2/19, 1(07 AM
def optimize(
target_name: str,
strategy_class: CtaTemplate,
setting: dict,
vt_symbol: str,
interval: Interval,
start: datetime,
rate: float,
slippage: float,
size: float,
pricetick: float,
capital: int,
end: datetime,
mode: BacktestingMode,
):
"""
Function for running in multiprocessing.pool
"""
engine = BacktestingEngine()
engine.set_parameters(
vt_symbol=vt_symbol,
interval=interval,
start=start,
rate=rate,
slippage=slippage,
size=size,
pricetick=pricetick,
capital=capital,
end=end,
mode=mode
)
engine.add_strategy(strategy_class, setting)
engine.load_data()
engine.run_backtesting()
engine.calculate_result()
statistics = engine.calculate_statistics()
target_value = statistics[target_name]
return (str(setting), target_value, statistics)
http://www.vnpy.com/docs/cn/cta_strategy.html#id2 Page 17 of 26
CTA策略略模块 10/2/19, 1(07 AM
pool = multiprocessing.Pool(multiprocessing.cpu_count())
results = []
for setting in settings:
result = (pool.apply_async(optimize, (
target_name,
self.strategy_class,
setting,
self.vt_symbol,
self.interval,
self.start,
self.rate,
self.slippage,
self.size,
self.pricetick,
self.capital,
self.end,
self.mode
)))
results.append(result)
pool.close()
pool.join()
return result_values
http://www.vnpy.com/docs/cn/cta_strategy.html#id2 Page 18 of 26
CTA策略略模块 10/2/19, 1(07 AM
def add_strategy(
self, class_name: str, strategy_name: str, vt_symbol: str, sett
ing: dict
):
"""
Add a new strategy.
"""
if strategy_name in self.strategies:
self.write_log(f" {strategy_name}")
return
strategy_class = self.classes[class_name]
self.put_strategy_event(strategy)
http://www.vnpy.com/docs/cn/cta_strategy.html#id2 Page 19 of 26
CTA策略略模块 10/2/19, 1(07 AM
def _init_strategy(self):
"""
Init strategies in queue.
"""
while not self.init_queue.empty():
strategy_name = self.init_queue.get()
strategy = self.strategies[strategy_name]
if strategy.inited:
self.write_log(f"{strategy_name}
")
continue
self.write_log(f"{strategy_name} ")
self.init_thread = None
http://www.vnpy.com/docs/cn/cta_strategy.html#id2 Page 20 of 26
CTA策略略模块 10/2/19, 1(07 AM
if strategy.trading:
self.write_log(f"{strategy_name} ")
return
self.call_strategy_func(strategy, strategy.on_start)
strategy.trading = True
self.put_strategy_event(strategy)
# Update GUI
self.put_strategy_event(strategy)
http://www.vnpy.com/docs/cn/cta_strategy.html#id2 Page 21 of 26
CTA策略略模块 10/2/19, 1(07 AM
self.update_strategy_setting(strategy_name, setting)
self.put_strategy_event(strategy)
# Remove setting
self.remove_strategy_setting(strategy_name)
return True
http://www.vnpy.com/docs/cn/cta_strategy.html#id2 Page 22 of 26
CTA策略略模块 10/2/19, 1(07 AM
def buy(self, price: float, volume: float, stop: bool = False, lock
: bool = False):
"""
Send buy order to open a long position.
"""
return self.send_order(Direction.LONG, Offset.OPEN, price, volu
me, stop, lock)
def sell(self, price: float, volume: float, stop: bool = False, loc
k: bool = False):
"""
Send sell order to close a long position.
"""
return self.send_order(Direction.SHORT, Offset.CLOSE, price, vo
lume, stop, lock)
def send_order(
self,
direction: Direction,
offset: Offset,
price: float,
volume: float,
stop: bool = False,
lock: bool = False
):
"""
Send a new order.
"""
if self.trading:
vt_orderids = self.cta_engine.send_order(
self, direction, offset, price, volume, stop, lock
)
return vt_orderids
else:
return []
http://www.vnpy.com/docs/cn/cta_strategy.html#id2 Page 23 of 26
CTA策略略模块 10/2/19, 1(07 AM
def send_order(
self,
strategy: CtaTemplate,
direction: Direction,
offset: Offset,
price: float,
volume: float,
stop: bool,
lock: bool
):
"""
"""
contract = self.main_engine.get_contract(strategy.vt_symbol)
if not contract:
self.write_log(f" {strategy.vt_symbol}", s
trategy)
return ""
if stop:
if contract.stop_supported:
return self.send_server_stop_order(strategy, contract,
direction, offset, price, volume, lock)
else:
return self.send_local_stop_order(strategy, direction,
offset, price, volume, lock)
else:
return self.send_limit_order(strategy, contract, direction,
offset, price, volume, lock)
def send_limit_order(
self,
strategy: CtaTemplate,
contract: ContractData,
direction: Direction,
offset: Offset,
price: float,
volume: float,
lock: bool
):
"""
Send a limit order to server.
"""
return self.send_server_order(
strategy,
contract,
direction,
offset,
price,
volume,
OrderType.LIMIT,
lock
)
def send_server_order(
self,
strategy: CtaTemplate,
contract: ContractData,
direction: Direction,
http://www.vnpy.com/docs/cn/cta_strategy.html#id2 Page 24 of 26
CTA策略略模块 10/2/19, 1(07 AM
offset: Offset,
price: float,
volume: float,
type: OrderType,
lock: bool
):
"""
Send a new order to server.
"""
# Create request and send order.
original_req = OrderRequest(
symbol=contract.symbol,
exchange=contract.exchange,
direction=direction,
offset=offset,
type=type,
price=price,
volume=volume,
)
# Send Orders
vt_orderids = []
self.offset_converter.update_order_request(req, vt_orderid)
return vt_orderids
http://www.vnpy.com/docs/cn/cta_strategy.html#id2 Page 25 of 26
CTA策略略模块 10/2/19, 1(07 AM
if yd_available:
req_yd = copy(req)
if self.exchange == Exchange.SHFE:
req_yd.offset = Offset.CLOSEYESTERDAY
else:
req_yd.offset = Offset.CLOSE
req_list.append(req_yd)
if open_volume:
req_open = copy(req)
req_open.offset = Offset.OPEN
req_open.volume = open_volume
req_list.append(req_open)
return req_list
http://www.vnpy.com/docs/cn/cta_strategy.html#id2 Page 26 of 26