0%

简介

quantstats – 衡量策略绩效指标的python lib库,用于投资组合分析。主要由3部分组成:

  • quantstats.stats:用于计算多种性能指标,如夏普比率、胜率等
  • quantstats.plots:用于性能、下降趋势、月度回报等绩效指标的可视化
  • quantstats.reports:用于生成度量报告,可保存为html文件

安装&使用

  • 安装:pip install quantstats
  • 使用方法:
  1. 使用quantstats.stats计算多种性能指标,如夏普比率、胜率等
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import quantstats as qs
qs.extend_pandas()
stock = qs.utils.download_returns('TSLA')
stock
Date
2010-06-29 NaN
2010-06-30 -0.002512
2010-07-01 -0.078472
2010-07-02 -0.125683
2010-07-06 -0.160938
...
2022-04-18 0.019584
2022-04-19 0.023758
2022-04-20 -0.049555
2022-04-21 0.032317
2022-04-22 -0.003698
Name: Close, Length: 2976, dtype: float64
qs.stats.sharpe(stock)
1.0828146689088534
stock.sharpe()
1.0828146689088534

支持的完整指标:

1
[f for f in dir(qs.stats) if f[0] != '_']
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
['adjusted_sortino',
'autocorr_penalty',
'avg_loss',
'avg_return',
'avg_win',
'best',
'cagr',
'calmar',
'common_sense_ratio',
'comp',
'compare',
'compsum',
'conditional_value_at_risk',
'consecutive_losses',
'consecutive_wins',
'cpc_index',
'cvar',
'distribution',
'drawdown_details',
'expected_return',
'expected_shortfall',
'exposure',
'gain_to_pain_ratio',
'geometric_mean',
'ghpr',
'greeks',
'implied_volatility',
'information_ratio',
'kelly_criterion',
'kurtosis',
'max_drawdown',
'monthly_returns',
'omega',
'outlier_loss_ratio',
'outlier_win_ratio',
'outliers',
'payoff_ratio',
'pct_rank',
'profit_factor',
'profit_ratio',
'r2',
'r_squared',
'rar',
'recovery_factor',
'remove_outliers',
'risk_of_ruin',
'risk_return_ratio',
'rolling_greeks',
'rolling_sharpe',
'rolling_sortino',
'rolling_volatility',
'ror',
'serenity_index',
'sharpe',
'skew',
'smart_sharpe',
'smart_sortino',
'sortino',
'tail_ratio',
'to_drawdown_series',
'ulcer_index',
'ulcer_performance_index',
'upi',
'value_at_risk',
'var',
'volatility',
'warn',
'win_loss_ratio',
'win_rate',
'worst']
  1. 使用quantstats.plots以图形的形式输出绩效指标
1
qs.plots.snapshot(stock, title="TSLA Performance')

支持的全部绘图函数:

1
[f for f in dir(qs.plots) if f[0] != '_']
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
['daily_returns',
'distribution',
'drawdown',
'drawdowns_periods',
'earnings',
'histogram',
'log_returns',
'monthly_heatmap',
'monthly_returns',
'plotly',
'returns',
'rolling_beta',
'rolling_sharpe',
'rolling_sortino',
'rolling_volatility',
'snapshot',
'to_plotly',
'warnings',
'yearly_returns']
  1. 使用quantstats.reports生成综合报表,可保存为html文件

qs.reports.html(stock, "SPY")

支持输出7种不同的报告:

  1. qs.reports.metrics(mode='basic|full", ...) - 展现基础/所有指标
  2. qs.reports.plots(mode='basic|full", ...) - 展现基础/所有绘图
  3. qs.reports.basic(...) - 展现基础指标和绘图
  4. qs.reports.full(...) - 展现所有指标和绘图
  5. qs.reports.html(...) - 生成html完整报告
1
[f for f in dir(qs.reports) if f[0] != '_']

['basic', 'full', 'html', 'iDisplay', 'iHTML', 'metrics', 'plots']

quantstats输出的html报表如下,可以看到左边是可视化绩效指标,右边是文字绩效指标。


在backtrader中使用quantstats

策略绩效评价是量化交易很重要的一环,backtrader提供多种分析者对象analyzer,可以输出各项策略绩效指标,但输出结果是字典方式的数据,没有可视化的绩效报表,而且还缺少一些重要指标,比如索提诺比率(sortino ratio),使用起来不友好。quantstats可以输出html报表,包括各项绩效指标和图表,且可以非常方便地与backtrader集成。

backtrader使用quantstats示例代码如下:

1
2
3
4
5
6
7
8
9
10
cerebro.addanalyzer(bt.analyzers.PyFolio, _name='pyfolio')
strats = cerebro.run()
strat0 = strats[0]
pyfolio = strats.analyzers.getbyname('pyfolio')
returns, positions, transactions, gross_lev = pyfoliozer.get_pf_items()
print(returns)
returns.index = returns.index.tz_convert(None)
import pandas as pd
import quantstats
quantstats.reports.html(returns, output='stats.html', title='Stock Sentiment')

交流

欢迎大家留言,关注微信公众号多多交流,最新的文章会优先发布在微信公众号上。

参考

简介

  • empyrical – Quantopian开源的常见金融风险指标lib库,会调用pandas_datareader从yahoo或google获取股票数据
  • pyfolio – Quantopian开源的用图形表示的金融投资组合性能和风险分析的Python库,基于empyrical获取数据和计算基础指标,由各种各样的独立图组成,这些图提供了交易策略表现的综合图像。图形示例可以参考full_tear_sheet_example.ipynb

empyrical安装&使用

  • 安装:pip install empyrical
  • 使用方法:
    以计算最大回撤和alpha、beta为例,代码如下。
1
2
3
4
5
6
7
8
9
import numpy as np
from empyrical import max_drawdown, alpha_beta
returns = np.array([.01, .02, .03, -.4, -.06, -.02])
benchmark_returns = np.array([.02, .02, .03, -.35, -.05, -.01])
max_drawdown(returns) # 计算最大回撤
alpha, beta = alpha_beta(returns, benchmark_returns) # 计算alpha和beta
returns = pd.Series([.01, .02, .03, -.4, -.06, -.02]) #支持pd.Series()
max_drawdown(returns)

查看empyrical支持的api列表,如下。

1
2
import empyrical
print(dir(empyrical))

结果是:

1
['DAILY', 'MONTHLY', 'QUARTERLY', 'WEEKLY', 'YEARLY', '__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__path__', '__spec__', '__version__', '_version', 'aggregate_returns', 'alpha', 'alpha_aligned', 'alpha_beta', 'alpha_beta_aligned', 'annual_return', 'annual_volatility', 'beta', 'beta_aligned', 'beta_fragility_heuristic', 'beta_fragility_heuristic_aligned', 'cagr', 'calmar_ratio', 'capture', 'compute_exposures', 'conditional_value_at_risk', 'cum_returns', 'cum_returns_final', 'deprecate', 'down_alpha_beta', 'down_capture', 'downside_risk', 'excess_sharpe', 'gpd_risk_estimates', 'gpd_risk_estimates_aligned', 'max_drawdown', 'omega_ratio', 'perf_attrib', 'periods', 'roll_alpha', 'roll_alpha_aligned', 'roll_alpha_beta', 'roll_alpha_beta_aligned', 'roll_annual_volatility', 'roll_beta', 'roll_beta_aligned', 'roll_down_capture', 'roll_max_drawdown', 'roll_sharpe_ratio', 'roll_sortino_ratio', 'roll_up_capture', 'roll_up_down_capture', 'sharpe_ratio', 'simple_returns', 'sortino_ratio', 'stability_of_timeseries', 'stats', 'tail_ratio', 'up_alpha_beta', 'up_capture', 'up_down_capture', 'utils', 'value_at_risk']

顺便说明下,empyrical官方api手册不全,看api文档使用help来看比较方便,如help(empyrical.excess_sharpe)

pyfolio安装&使用

pyfolio只能在jupyter notebook环境下完整绘图,在命令行环境或py文件下可以单独画图,但不能显示表格数据。

通常的误区是:pyfolio只能在jupyter下使用。正确的说法是pyfolio对jupyter环境下支持的最好。

  • 安装:
1
pip install git+https://github.com/quantopian/pyfolio

使用pip install pyfolio,在使用的时候会报错,下面会说明。

  • 使用方法:
  1. 构造数据
    产出如下数据,格式为pd.series。
1
data.head()
1
2
3
4
5
6
7
Date
2017-04-25 00:00:00+00:00 0.018699
2017-04-26 00:00:00+00:00 -0.011536
2017-04-27 00:00:00+00:00 -0.004965
2017-04-28 00:00:00+00:00 0.017626
2017-05-01 00:00:00+00:00 0.027892
dtype: float64
  1. 使用pyfolio
1
2
3
import pyfolio as pf
pf.create_returns_tear_sheet(data)
pf.plot_drawdown_periods(data)

在jupyter中运行,结果如下:




在ipython运行,结果如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
In [8]: pf.create_returns_tear_sheet(data)
<IPython.core.display.HTML object>
<IPython.core.display.HTML object>

In [9]: ret = pf.create_returns_tear_sheet(data)
<IPython.core.display.HTML object>
<IPython.core.display.HTML object>

pf.plot_drawdown_periods(data)

import matplotlib.pyplot as plt

plt.show()

  • 查看支持的函数:
1
print(dir(pf))

['APPROX_BDAYS_PER_MONTH', 'FACTOR_PARTITIONS', 'FigureCanvasAgg', 'FuncFormatter', 'MM_DISPLAY_UNIT', 'Markdown', 'OrderedDict', 'STAT_FUNCS_PCT', '__all__', '__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__path__', '__spec__', '__version__', '_seaborn', '_version', 'axes_style', 'capacity', 'create_capacity_tear_sheet', 'create_full_tear_sheet', 'create_interesting_times_tear_sheet', 'create_perf_attrib_tear_sheet', 'create_position_tear_sheet', 'create_returns_tear_sheet', 'create_round_trip_tear_sheet', 'create_simple_tear_sheet', 'create_txn_tear_sheet', 'customize', 'datetime', 'deprecate', 'display', 'division', 'ep', 'figure', 'gridspec', 'interesting_periods', 'matplotlib', 'np', 'patches', 'pd', 'perf_attrib', 'plot_annual_returns', 'plot_capacity_sweep', 'plot_cones', 'plot_daily_turnover_hist', 'plot_daily_volume', 'plot_drawdown_periods', 'plot_drawdown_underwater', 'plot_exposures', 'plot_gross_leverage', 'plot_holdings', 'plot_long_short_holdings', 'plot_max_median_position_concentration', 'plot_monthly_returns_dist', 'plot_monthly_returns_heatmap', 'plot_monthly_returns_timeseries', 'plot_perf_stats', 'plot_prob_profit_trade', 'plot_return_quantiles', 'plot_returns', 'plot_rolling_beta', 'plot_rolling_returns', 'plot_rolling_sharpe', 'plot_rolling_volatility', 'plot_round_trip_lifetimes', 'plot_sector_allocations', 'plot_slippage_sensitivity', 'plot_slippage_sweep', 'plot_turnover', 'plot_txn_time_hist', 'plotting', 'plotting_context', 'plt', 'pos', 'pytz', 'round_trips', 'show_and_plot_top_positions', 'show_perf_stats', 'show_profit_attribution', 'show_worst_drawdown_periods', 'sns', 'sp', 'tears', 'time', 'timer', 'timeseries', 'txn', 'utils', 'warnings', 'wraps']

  • 常见错误
  1. 报错:ValueError: The truth value of a Series is ambiguous. Use a.empty, a.bool(), a.item(), a.any() or a.all()

解决办法:pf.create_returns_tear_sheet()的参数是pd.series,不能是pd.dataframe

  1. 报错:AttributeError: ‘numpy.int64’ object has no attribute ‘to_pydatetime’

解决办法:

1
pip install git+https://github.com/quantopian/pyfolio

在backtrader中使用PyFolio

pyfolio改变过api接口,create_full_tear_sheet()函数后面没有了gross_lev参数,使用backtrade网站的示例代码会报错。 参考pyfolio官方的使用文档即可。

backtrader使用pyfolio示例代码如下:

1
2
3
4
5
6
7
cerebro.addanalyzer(bt.analyzers.PyFolio, _name='pyfolio')
strats = cerebro.run()
strat0 = strats[0]
pyfolio = strats.analyzers.getbyname('pyfolio')
returns, positions, transactions, gross_lev = pyfoliozer.get_pf_items()
import pyfolio as pf
pf.create_full_tear_sheet(returns)

交流

欢迎大家留言,关注微信公众号多多交流,最新的文章会优先发布在微信公众号上。

参考

最近使用markdown写文档越来越多了,有些成体系的文章希望逐步整理成小册子或者小文档,不排除后面有时间了整理成书籍。
于是调研了下专门用于制作电子书类文档的工具,之前听说比较多的是gitbook和Read the Docs。不过gitbook的开源版本2018年末就不更新了,尝试折腾了挺久都不好使。于是网上找到了几个候选:mdbook、bookdown、mkdocs、gohugo、和peach。mdbook则是用rust语言实现的, 只有一个单独的命令行程序,能够实时渲染,最近开发迭代还比较多。
bookdown是r语言实现的,依赖于RStudio集成环境制作;mkdocs是python实现的,gohugo和peach是go语言实现的。由于mdbook尝试了下能够比较好的满足我的需求,其他就没有深入去尝试了,感兴趣的读者可以自己去试试。

mdbook介绍

mdbook是一个用markdown来创建书籍的命令行工具,非常适合用来创建产品、api文档、手册、课程材料等。
特点:

  • 轻量级markdown语法
  • 集成了搜索功能
  • 代码块语法高亮支持
  • 多个主题支持
  • 快速、安全、简单
  • 书籍The Rust Programming Language book也在使用mdbook来编写

安装

  1. 手动下载安装
    去github 下载,点下载链接,支持windows, mac, linux。
    下载解压后,将mdbook放到/usr/local/bin下即可使用

  2. mac可以使用brew安装,安装的版本可能不是最新,但比较方便

    1
    brew install  mdbook

使用

1
2
3
4
mkdir my-quant-book
cd my-quant-book
mdbook init # 会提示输入文档标题
mdbook serve

浏览器输入http://localhost:3000/ 就可以看到书籍了。
在my-quant-book下生成了book和src两个文件夹和book.toml一个配置文件。
在src目录下自动生成了SUMMARY.md和chapter_1.md 2个markdown文件。chapter_1.md和普通markdown文件一样,SUMMARY.md比较特殊,用来表示文档包含那些文件以及他们的顺序是咋样的。

mdbook服务默认启动端口是3000,如果需要更改端口,可以使用-p参数,如mdbook serve -p 3001 将端口改为3001。

其他跟markdown一样正常编辑就好了。不知道markdown语法的可以参考我的另外一篇《markdown实战》文章。

交流

欢迎关注微信公众号交流~

  • 微信公众号:诸葛说talk

参考

一、TA-Lib介绍

  • TA-Lib – 交易软件开发广泛使用的技术分析lib,包括了200多个技术指标,如MACD, RSI等
  • ta-lib for python – python封装的ta-lib。python封装的ta-lib,使用Cython和Numpy高效实现,比使用SWIG接口的原始版本快2-4倍

二、安装

mac安装方法如下所示:

1
2
$ brew install ta-lib
$ pip install TA-Lib

如果没用brew安装ta-lib,会报如下错误

1
2
3
func.c:256:28: fatal error: ta-lib/ta_libc.h: No such file or directory
compilation terminated.
If you get build errors like this, it typically means that it can't find the underlying TA-Lib library and needs to be installed:

windows、linux参考:https://mrjbq7.github.io/ta-lib/install.html

进python使用import talib没有报错的话,表明安装成功。

三、常用指标使用

  1. SMA:简单移动平均线(Simple Moving Average)
    talib.SMA() 要求数据是numpy.ndarray格式
    talib.abstract.SMA() 要求数据是Numpy数组的字典格式
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import numpy as np
import talib

close = np.random.random(100)
output = talib.SMA(close) # 默认是SMA30
output = talib.SMA(close, timeperiod=5) # SMA5

inputs = {
'open': np.random.random(100),
'high': np.random.random(100),
'low': np.random.random(100),
'close': np.random.random(100),
'volume': np.random.random(100)
}
from talib.abstract import *
output = SMA(input_arrays, timeperiod=25) # 默认对close价格计算
output = SMA(input_arrays, timeperiod=25, price='open') # 对open价格计算
  1. EMA:指数移动平均线(Exponential Moving Average)

    1
    2
    talib.EMA(close)
    talib.abstract.EMA(inputs)
  2. MACD:平滑异同移动平均线(Moving Average Convergence / Divergence)
    通过三种数据的信号(均线的组合 )可以判断趋势的力量和方向并确定趋势的转折点

    1
    2
    talib.MACD(close)
    talib.abstract.MACD(inputs)
  3. 支持的指标列表

  • 均线指标,如EMA、SMA、WMA等
  • 动量指标,如MACD、MOM、RSI等
  • 成交量指标,如AD、OBV等
  • 易变指标,如ATR、NATR等
  • 价格变换,如AVGPRICE、MEDPRICE等
  • 循环指标,如HT_DCPERIOD、HT_SINE等
  • 模式识别,如CDL2CROWS、CDLHAMMER等
  • 统计函数,如VAR,STDDEV, LINEARREG等
  • 数学变换,如ACOS、ASIN、CEIL、COS、EXP、LN、SQRT等
  • 数学操作,如ADD、DIV、MAX、MULT、SUM等

支持的功能及函数列表如下:

1
2
3
4
5
import talib
talib.get_functions()
print(len(talib.get_functions()))
talib.get_function_groups()
print(len(talib.get_function_groups()))

四、在backtrader中调用TA-Lib库

为了满足大家的使用习惯,Backtrader也接入了 TA-Lib 技术指标库,具体信息可以查阅官方 document,文档中对各个函数的输入、输出,以及在 Backtrader 中特有的绘图参数、返回的 lines 属性等信息都做了介绍和说明。TA-Lib 指标函数的调用形式为 bt.talib.xxx,跟直接使用ta-lib区别不大 :

1
2
3
4
5
6
7
8
class TALibStrategy(bt.Strategy):
def __init__(self):
# 计算 5 日均线
bt.talib.SMA(self.data.close, timeperiod=5)
bt.indicators.SMA(self.data, period=5)
# 计算布林带
bt.talib.BBANDS(self.data, timeperiod=25)
bt.indicators.BollingerBands(self.data, period=25)

交流

欢迎关注微信公众号交流,最新的文章会优先发布在微信公众号上。

  • 微信公众号:诸葛说talk

参考

最近很多人在咨询 SKA 框架的情况,整理了一些资料,欢迎交流沟通~

1. 什么是SKAdNetwork

SKAdNetwork 是 Apple于2018年5月推出 的归因框架,可以在保护用户隐私的同时进行APP归因,但之前由于idfa 获取不需每个 app 单独授权,SKAdNetwork并没有得到广泛使用。 直至2020年6月22日举行的WWDC(全球开发者大会)上,苹果宣布了在 iOS 14 系统中,App 在获取 IDFA 时需要明确请求用户的许可。这就意味着如果未经过用户允许将获取不到 idfa,这让过去通过 IDFA 来实现的广告归因和效果衡量变得接近无效或者效果损失很大。 我们在广告系统中确实遇到了 cvr 大幅下降的问题,随着 ios 14.5之后的 ios 版本覆盖越来越多,归因问题越来越严重。SKN 框架也得到了越来越多人的重视。

2. SkAdNetwork的优点和缺点是什么?

SKAdNetwork的优势是确定性归因,其能提供几乎 100% 精确的归因。有数据表明,与 IDFA 精确归因相比,SKAdNetwork 的准确性只差了 2%。需要说明的是,如果某个推广活动之前通过 IDFA 归因获得了 1000 次安装归因,SKAdNetwork 可能会归因 900 次安装和 100 次重装。这是因为 SKAdNetwork 只会为每个 iTunes 账户归因一次安装。因此,为了与 ATT (AppTrackingTransparency授权弹窗)执行前的情况保持一致,分析安装和重装的总量非常重要。

SKAdNetwork 的缺点是无法像 IDFA 一样实时将转化跟点击精确关联起来。 具体如下:

  • 无法精确归因到点击,原因是无法将点击标记和转化精确关联起来。
  • 无法实时归因,SKA框架最少 24 至 48 小时的转化数据延迟回传。
  • SKAdNetwork 框架下每个渠道仅显示 100 个不同的推广活动,且能提供的数据信号非常有限,这对于稍微大点的客户来说经常不够用。 按照当前的计划,SKAdNetwork 会提供长度为 6 比特的下游指标,且有 24 小时的时间限制。每次用户触发应用内事件,该 6 比特指标就会发生变化,成为应用指定的全新 6 比特事件识别码,而时间限制也会延长 24 小时。事件窗口过期后,第二个 24 小时归因窗口就会开始计时。SKAdNetwork 会在这 24 小时窗口内随机返回归因数据。
  • 未涵盖所有的归因链路,比如移动网页端就无法归因
  • 由于无法实时精确归因,导致归因流程中作弊风险大幅加大。同时数据由广告平台所有并提供报告,会导致不信任感加大,当然这块 ios 也在升级解决中。

3. SkAdNetwork怎么用?

Diagram showing a user tapping an ad for app B inside of app A, then installing and launching app B, which triggers a conversion notification after app B calls one of two methods, and after the timer expires. The ad network receives the postback which it must verify.
SKA框架流程如上图所示,看了上面的说明,基本能知道每个步骤是在干啥了,不展开说明了。下面说明下各个参与方都需要做什么。

3.1 广告平台/广告网络需要做什么?

这里的广告平台包括腾讯、阿里、字节、百度等头部媒体,也包括appsflyer、adjust、热云等第三方平台。

a) 在Apple 上注册Network ID,用于在广告活动时使用归因验证的各种API。

b) 为流量媒体侧App(Source App)提供已签名的广告应用。广告平台(Ad Network)在收到媒体端的广告请求时为广告应用进行签名(可以理解为生成一个广告的追踪ID)。

c) 通过注册的回包网址(Postback URL)接收来自广告主回传的激活和转化信息;

d) 确认已接收广告主回传的信息。

3.2 媒体需要做什么?

  1. 需要在媒体应用的Info.plist 上添加广告网络的ID;
  2. 展示已签名的广告。 在广告即将曝光前,调用系统的loadProduct(withParameters:completionBlock) 函数,用于预加载一个App Store的web端或者客户端的广告展示落地页。这样可以提升广告展示的速度,同时,将广告的应用相关签名信息和广告网络ID(Ad network ID)等信息传给App Store。

3.3 广告主/开发者需要做什么?

  1. 在应用安装激活后,应用调用系统的API registerAppForAdNetworkAttribution或updateConversionValue函数发送激活或其他转化信息
  2. 如果此次安装有归因数据,那么应用首次调用函数registerAppForAdNetworkAttribution 会生成通知,并且启动一个 24 小时计时器,再次调用该函数没有反应。但是可以调用 updateConversionValue函数提供转化数值并且重启计时器。在计时器结束后的 0-24 小时内设备会将安装通知发送给广告网络,广告网络在收到通知后必须进行验证
  3. updateConversionValue函数的参数为conversionValue,类型为无符号的 6 bit 整数(0-63)。由广告主应用和广告网络决定此值的含义,默认值为0。开发者可以在 24小时的循环周期内反复调用 updateConversionValue函数来更新转化数值。转化数值是由广告网络或者广告主定义的 6 bit 值。App在计时器结束前可以随意调用。每次调用,只要这个值比上一次大,计时器就会重新计时。当计时器结束,最后的数值将生效。之后继续调用 updateConversionValue 无任何作用。在计时器结束后的 0-24 小时内设备将安装通知发送给广告网络。
  4. SKAdNetwork 系统分享的数据都采取聚合形式,不提供用户层级上的精细数据,事件识别码只能向上叠进。只要这个值比上一次大,计时器就会重新计时。要解决这个问题,开发者需要为排列组合中所有的可能性分配不同的比特值,而不是为每种事件分配比特值。

4. 归因的时间窗口是多少?

从广告曝光到广告网络接收到安装验证的消息最小延迟是24-48小时,测试的时候可以缩小到5-10分钟,具体可以参考Testing Ad Attributions with a Downloaded Profile. 各个事件有最长归因时间窗口,超过该窗口发生的转化无法归因到对应的事件上,具体如下。

事件 时间窗口
广告网络展示了一个StoreKit渲染的广告 用户有30天的时间窗口来安装 app
广告网链展示了一个浏览广告 用户有24小时窗口来安装 app
用户安装了 app 用户有60天窗口来启动 app
用户启动 app 且 app 调用了 registerAppForAdNetworkAttribution()函数 设备在24小时定时器到期后在0-24小时内随机发送安装-验证回传信号
用户启动 app 且 app 调用了updateConversionValue函数 设备在最后一次调用updateConversionValue函数的24小时定时器到期后在0-24小时内随机发送安装-验证回传信号

术语

  • IDFV - Identifier For Vendor(应用开发商标识符)
  • IDFA - Identifier For Advertising(广告标识符)
  • mmp - mobile measure partner (移动成效衡量合作伙伴)

参考

交流

我发文章的几个地方,欢迎大家在朋友圈等地方分享,多多交流。

1. 简介

backtrader 是一个用于回测和交易的python框架,它功能丰富,可以让你聚焦在设计可重用的交易策略、指标和分析上,而不用花大量时间在构建基础框架上面。

优点:

  • github开源,策略编写简单快速
  • 安装方便,除了matplotlib外,不依赖其他外部lib
  • 支持ib等券商实时交易
  • 数据来源支持csv文件,在线数据源或pandas格式,同时支持多数据来源、多策略
  • 支持TA-lib指标,方便支持自定义指标的开发,集成pyfolio分析模块等
  • 支持品种多,运行速度快:pandas 矢量运算、多策略并行运算

缺点:

  • gpl 3.0授权,更改框架需要开源
  • 画图界面风格比较老旧
  • 框架代码抽象比较多,使用了大量的元编程,学习比较费劲

2. 安装

1
2
3
4
pip install backtrader
git clone https://github.com/mementum/backtrader.git
cd samples/commission-schemes
python commission-schemes.py --plot

出现如下提示&图形,表明安装正常。

1
2
3
4
5
6
7
8
2006-03-09, BUY CREATE, 3757.59
2006-03-10, BUY EXECUTED, Price: 3754.13, Cost: 2000.00, Comm 2.00
2006-04-11, SELL CREATE, 3788.81
2006-04-12, SELL EXECUTED, Price: 3786.93, Cost: 2000.00, Comm 2.00
2006-04-12, TRADE PROFIT, GROSS 328.00, NET 324.00
2006-04-20, BUY CREATE, 3860.00
2006-04-21, BUY EXECUTED, Price: 3863.57, Cost: 2000.00, Comm 2.00
.......

图形
如果出现如下错误,说明matplotlib安装不对,ImportError: cannot import name 'warnings' from 'matplotlib.dates'
解决办法:pip install matplotlib==3.2.2 -i https://pypi.tuna.tsinghua.edu.cn/simple

3. 代码框架介绍

backtrader代码运行主要包括以下组成部分:

  1. Strategy交易策略模块:需要设计交易策略,根据信号进行买入/卖出
  • 设计策略中用于生成交易信号的指标
  • 编写买入、卖出的交易逻辑
  • 按需打印交易信息
  1. DataFeeds数据模块: 将目标金融数据加载到回测框架中
  2. Cerebro回测框架设置:根据需要设置初始资金,佣金,数据来源,交易策略,交易头寸大小。通过Broker经纪商模块设置
  3. 运行回测:运行Cerebro回测并打印出所有已执行的交易
  4. 按需添加策略分析指标Analyzers或观测器Observers评估效果: 以图形和风险收益等指标对交易策略的回测结果进行评价

Lines说明:Lines是backtrader回测的数据,由一系列的点组成,通常包括以下类别的数据:Open(开盘价), High(最高价), Low(最低价), Close(收盘价), Volume(成交量), OpenInterest(未平仓量,没有的话设置为0)。Data Feeds(数据加载)、Indicators(技术指标)和Strategies(策略)都会生成 Lines。价格数据中的所有”Open” (开盘价)按时间组成一条 Line。所以,一组含有以上6个类别的价格数据,共有6条 Lines。如果算上“DateTime”(时间,可以看作是一组数据的主键),一共有7条 Lines。当访问一条 Line 的数据时,会默认指向下标为 0 的数据,用于访问当前时刻。backtrader会将”0”一直指向当前值,下标 -1 来访问上一个值。比如:

1
2
3
self.dataclose[0] # 当日的收盘价
self.dataclose[-1] # 昨天的收盘价
self.dataclose[-2] # 前天的收盘价

其他说明:

1
2
3
4
5
6
7
self.sma5 = bt.indicators.SimpleMovingAverage(
self.datas[0], period=5) # 返回MA5的相关数据

cerebro.broker.setcash(100000.0) # 设定初始资金
cerebro.broker.setcommission(0.005) # 每次交易都需要支付一定的佣金
cerebro.broker.getvalue() # 目前的资金
cerebro.addsizer(bt.sizers.FixedSize, stake=100) # 设定每次交易买入的股数

以commission-schemes.py为例进行说明,代码如下,对应位置加上了注释说明。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
import argparse 
import datetime

# 导入backtrader相关包
import backtrader as bt
import backtrader.feeds as btfeeds
import backtrader.indicators as btind

# 交易策略
class SMACrossOver(bt.Strategy):
params = (
('stake', 1), # 交易股数
('period', 30), # 周期长度
)

def log(self, txt, dt=None):
''' Logging function fot this strategy'''
dt = dt or self.datas[0].datetime.date(0)
print('%s, %s' % (dt.isoformat(), txt))

# 打印订单信息,可选
def notify_order(self, order):
if order.status in [order.Submitted, order.Accepted]:
# Buy/Sell order submitted/accepted to/by broker - Nothing to do
return

# Check if an order has been completed
# Attention: broker could reject order if not enougth cash
if order.status in [order.Completed, order.Canceled, order.Margin]:
if order.isbuy():
self.log(
'BUY EXECUTED, Price: %.2f, Cost: %.2f, Comm %.2f' %
(order.executed.price,
order.executed.value,
order.executed.comm))
else: # Sell
self.log('SELL EXECUTED, Price: %.2f, Cost: %.2f, Comm %.2f' %
(order.executed.price,
order.executed.value,
order.executed.comm))

# 打印交易信息,可选
def notify_trade(self, trade):
if trade.isclosed:
self.log('TRADE PROFIT, GROSS %.2f, NET %.2f' %
(trade.pnl, trade.pnlcomm))

# 初始化策略属性、指标,必须
def __init__(self):
sma = btind.SMA(self.data, period=self.p.period)
# > 0 crossing up / < 0 crossing down
self.buysell_sig = btind.CrossOver(self.data, sma)

# 交易逻辑实现,必须
def next(self):
if self.buysell_sig > 0:
self.log('BUY CREATE, %.2f' % self.data.close[0])
self.buy(size=self.p.stake) # keep order ref to avoid 2nd orders

elif self.position and self.buysell_sig < 0:
self.log('SELL CREATE, %.2f' % self.data.close[0])
self.sell(size=self.p.stake)


def runstrategy():
args = parse_args()

# 实例化cerebro
cerebro = bt.Cerebro()

# Get the dates from the args
fromdate = datetime.datetime.strptime(args.fromdate, '%Y-%m-%d')
todate = datetime.datetime.strptime(args.todate, '%Y-%m-%d')

# 从csv文件读取数据
data = btfeeds.BacktraderCSVData(
dataname=args.data,
fromdate=fromdate,
todate=todate)

# 将数据传给cerebro
cerebro.adddata(data)

# 添加策略
cerebro.addstrategy(SMACrossOver, period=args.period, stake=args.stake)

# 设置初始资金
cerebro.broker.setcash(args.cash)

commtypes = dict(
none=None,
perc=bt.CommInfoBase.COMM_PERC,
fixed=bt.CommInfoBase.COMM_FIXED)

# 设置交易佣金
cerebro.broker.setcommission(commission=args.comm,
mult=args.mult,
margin=args.margin,
percabs=not args.percrel,
commtype=commtypes[args.commtype],
stocklike=args.stocklike)

# 启动回测
cerebro.run()

# 绘图
if args.plot:
cerebro.plot(numfigs=args.numfigs, volume=False)


# 从命令行解析参数
def parse_args():
parser = argparse.ArgumentParser(
description='Commission schemes',
formatter_class=argparse.ArgumentDefaultsHelpFormatter,)

parser.add_argument('--data', '-d',
default='../../datas/2006-day-001.txt',
help='data to add to the system')

parser.add_argument('--fromdate', '-f',
default='2006-01-01',
help='Starting date in YYYY-MM-DD format')

parser.add_argument('--todate', '-t',
default='2006-12-31',
help='Starting date in YYYY-MM-DD format')

parser.add_argument('--stake', default=1, type=int,
help='Stake to apply in each operation')

parser.add_argument('--period', default=30, type=int,
help='Period to apply to the Simple Moving Average')

parser.add_argument('--cash', default=10000.0, type=float,
help='Starting Cash')

parser.add_argument('--comm', default=2.0, type=float,
help=('Commission factor for operation, either a'
'percentage or a per stake unit absolute value'))

parser.add_argument('--mult', default=10, type=int,
help='Multiplier for operations calculation')

parser.add_argument('--margin', default=2000.0, type=float,
help='Margin for futures-like operations')

parser.add_argument('--commtype', required=False, default='none',
choices=['none', 'perc', 'fixed'],
help=('Commission - choose none for the old'
' CommissionInfo behavior'))

parser.add_argument('--stocklike', required=False, action='store_true',
help=('If the operation is for stock-like assets or'
'future-like assets'))

parser.add_argument('--percrel', required=False, action='store_true',
help=('If perc is expressed in relative xx% rather'
'than absolute value 0.xx'))

# -p或--plot 需要画图
parser.add_argument('--plot', '-p', action='store_true',
help='Plot the read data')

parser.add_argument('--numfigs', '-n', default=1,
help='Plot using numfigs figures')

return parser.parse_args()

# 主函数
if __name__ == '__main__':
runstrategy()

交流

以下是发文章的几个地方。欢迎关注微信公众号,最新的文章会优先发布在微信公众号上。

参考

rqalpha简介

  • rqalpha米筐量化开源的从数据获取、算法交易、回测引擎、实盘模拟、实盘交易到数据分析的程序化交易框架。跟quantopian开源的zipline从api到本地运行方式都比较类似

优点:

  • rqalpha简单易学,能很快上手
  • rqalpha具有灵活的配置方式和比较强大的扩展性,可以比较容易地定制
  • rqalpha所有的策略都可以直接在 Ricequant上进行回测和实盘模拟,并且可以通过微信和邮件实时推送交易信号

缺点:

  • rqalpha不支持港美股回测&交易,可以自定义支持,但成本不小
  • rqalpha仅限非商业使用,如需商业使用,需要联系官方
  • Ricequant实盘模拟需要开通企业版
  • rqalpha本身支持不同周期的回测和实盘交易,但是目前只免费开放A股市场日线数据,如果用户需要做分钟回测或者更细级别的回测可以在 Ricequant上进行,也通过实现数据层接口函数来使用自己的数据

rqalpha安装

1
pip install rqalpha

RiceQuant免费提供日级别的股票、常用指数、场内基金和期货数据供回测使用。数据每个月月初更新,可以通过以下命令来下载和更新:
$ rqalpha download-bundle
bundle 默认存放在 ~/.rqalpha 下,也可以指定 bundle 的存放位置
$ rqalpha download-bundle -d target_bundle_path
如果使用了指定路径来存放 bundle,那么执行程序的时候也同样需要指定对应的 bundle 路径。
$ rqalpha run -d target_bundle_path .....

如果申请了免费试用(免费试用15天,试用账户进行了每天 50MB 的配额限制,申请链接)或者付费购买了米筐数据服务,可以使用 RQDatac 在每日盘后即时更新回测数据,更新命令如下:
$ rqalpha update-bundle

  • 运行以下命令,将会在指定目录生成一个examples文件夹,其中包含几个有趣的样例策略:
    $ rqalpha examples -d ./

  • 运行回测

    1
    2
    $ cd examples
    $ rqalpha run -f rsi.py -s 2020-01-01 -e 2021-01-01 -o result.pkl --plot --progress --account stock 100000
  • 绘制回测结果:如果运行完回测后,还需要再次绘制回测结果,可以运行以下命令:
    $ rqalpha plot result.pkl

rqalpha使用

rqalpha抽离了策略框架的所有技术细节,以API的方式提供给策略研发者用于编写策略,从而避免陷入过多的技术细节。

rqalpha的 API主要分为约定函数、数据查询接口、交易接口等几类。

  1. 约定函数: 作为 API 的入口函数,用户必须实现对应的约定函数才可以正确的使用RQAlpha

    1
    2
    3
    4
    * init() : 初始化方法,会在程序启动的时候执行
    * handle_bar(): bar数据更新时会自动触发调用
    * before_trading(): 会在每天策略交易开始前调用
    * after_trading(): 会在每天交易结束后调用

    示例代码如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    # 在这个方法中编写任何的初始化逻辑。context对象将会在你的算法策略的任何方法之间做传递。
    def init(context):
    # 在context中保存全局变量
    context.s1 = "000001.XSHE"
    # 实时打印日志
    logger.info("RunInfo: {}".format(context.run_info))

    # before_trading此函数会在每天策略交易开始前被调用,当天只会被调用一次
    def before_trading(context):
    logger.info("开盘前执行before_trading函数")

    # 你选择的证券的数据更新将会触发此段逻辑,例如日或分钟历史数据切片或者是实时数据切片更新
    def handle_bar(context, bar_dict):
    logger.info("每一个Bar执行")
    logger.info("打印Bar数据:")
    logger.info(bar_dict[context.s1])

    # after_trading函数会在每天交易结束后被调用,当天只会被调用一次
    def after_trading(context):
    logger.info("收盘后执行after_trading函数")
  2. 数据查询接口
    需要获取数据,根据数据来确定我们的仓位逻辑,因此会使用到数据查询的 API接口。

1
2
3
4
5
6
7
8
9
10
11
* all_instruments() : 获取所有合约基础信息数据
* instruments() : 获取合约详细数据
* history_bars() : 获取某一合约的历史数据
* current_snapshot() : 获取当前快照数据
* get_future_contracts() : 获取期货可以交易合约列表
* get_trading_dates(): 获取交易日列表
* get_previous_trading_date() : 获取上一日交易日
* get_next_trading_date() : 获取下一个交易日
* get_yield_curve(): 获取收益率曲线
* is_suspended() : 判断某股票当天是否停牌
* is_st_stock() : 判断某股票是否为 *st
  1. 交易接口
    rqalpha提供了多种交易接口,以方便不同的使用需求。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    * order_shares(): 【股票专用】指定股数交易
    * order_lots(): 【股票专用】指定手数交易
    * order_value(): 【股票专用】指定价值交易
    * order_percent():【股票专用】 一定比例下单
    * order_target_value(): 【股票专用】按照目标价值下单
    * order_target_percent(): 【股票专用】按照目标比例下单
    * buy_open(): 【期货专用】买开
    * sell_close():【期货专用】 平买仓
    * sell_open(): 【期货专用】卖开
    * buy_close(): 【期货专用】平卖仓
    * cancel_order(): 撤单
    * get_open_orders(): 获取未成交订单数据

rsi.py示例代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
from rqalpha.apis import *

import talib

# 在这个方法中编写任何的初始化逻辑。context对象将会在你的算法策略的任何方法之间做传递。
def init(context):

# 选择我们感兴趣的股票
context.s1 = "000001.XSHE"
context.s2 = "601988.XSHG"
context.s3 = "000068.XSHE"
context.stocks = [context.s1, context.s2, context.s3]

context.TIME_PERIOD = 14
context.HIGH_RSI = 85
context.LOW_RSI = 30
context.ORDER_PERCENT = 0.3

# 你选择的证券的数据更新将会触发此段逻辑,例如日或分钟历史数据切片或者是实时数据切片更新
def handle_bar(context, bar_dict):
# 开始编写你的主要的算法逻辑

# bar_dict[order_book_id] 可以拿到某个证券的bar信息
# context.portfolio 可以拿到现在的投资组合状态信息

# 使用order_shares(id_or_ins, amount)方法进行落单

# TODO: 开始编写你的算法吧!

# 对我们选中的股票集合进行loop,运算每一只股票的RSI数值
for stock in context.stocks:
# 读取历史数据
prices = history_bars(stock, context.TIME_PERIOD+1, '1d', 'close')

# 用Talib计算RSI值
rsi_data = talib.RSI(prices, timeperiod=context.TIME_PERIOD)[-1]

cur_position = get_position(stock).quantity
# 用剩余现金的30%来购买新的股票
target_available_cash = context.portfolio.cash * context.ORDER_PERCENT

# 当RSI大于设置的上限阀值,清仓该股票
if rsi_data > context.HIGH_RSI and cur_position > 0:
order_target_value(stock, 0)

# 当RSI小于设置的下限阀值,用剩余cash的一定比例补仓该股
if rsi_data < context.LOW_RSI:
logger.info("target available cash caled: " + str(target_available_cash))
# 如果剩余的现金不够一手 - 100shares,那么会被ricequant 的order management system reject掉
order_value(stock, target_available_cash)

多种方式运行策略

  • 命令行运行:rqalpha run -f rsi.py -s 2020-01-01 -e 2021-01-01 -o result.pkl –plot –progress –account stock 100000
  • 使用配置文件运行策略: rqalpha在运行策略时候会在当前目录下寻找 config.yml 或者 config.json 文件作为用户配置文件来读取,可以创建config.yml 配置文件,里面配置项为strategy_file: .buy_and_hold.py
  • 策略内配置参数信息
  • 通过引用 rqalpha库在代码中运行策略:使用 run_file、run_code、 run_func函数来运行策略

创建mod

rqalpha提供了拓展性较强的Mod Hook接口,这意味着开发者可以比较容易的对接第三方库。

1
2
3
$ rqalpha mod list # 查看当前安装的 Mod 列表及状态
$ rqalpha mod enable xxx # 启用
$ rqalpha mod disable xxx # 关闭
  • 扩展rqalpha API:如果你想为 rqalpha 创建自己的 API,可以通过 Mod 来注册新的 API。在内建的 mod 中,有一个 FuncatAPIMod,将通达信、同花顺的公式表达能力移植到python中,扩展了 rqalpha的 API

  • 扩展rqalpha实现自有数据的读取:rqalpha不限制本地运行的策略调使用哪些库,因此可以直接在策略中读取文件、访问数据库等,但需要关注如下两个注意事项:

    • 请在 init, before_trading, handle_bar, handle_tick, after_trading 等函数中读取自有数据,而不要在函数外执行数据获取的代码,否则可能会产生异常。
    • rqalpha是读取策略代码并执行的,因此实际当前路径是运行 rqalpha 命令的路径,策略使用相对路径容易产生异常。如果您需要根据策略路径来定位相对路径可以通过context.config.base.strategy_file 来获取策略路径,从而获取相对策略文件的其他路径
  • rqalpha采用logbook 作为默认的日志模块,可以通过在 mod 中为 logger添加 handler 实现自定义的日志收集

诸葛说 基于rqalpha文档行情数据 - 五十行代码接入 tushare 行情数据完善了tushare mod接口,增加了对tspro接口的支持,参见rqalpha_mod_tushare

交流

我发文章的几个地方,欢迎大家在朋友圈等地方分享,多多交流。

参考

简介

  • VeighNa – 基于Python的开源量化交易系统开发框架, 之前叫vnpy,最近改名叫VeighNa了,官网是 https://www.vnpy.com , 对应的产品是VeighNa Studio。 不是 http://www.vnpy.cn ,其对应的产品是VN Trader 。百度搜vnpy出来的是https://www.vnpy.cn。 不要搞混了,这两之前在打官司。 VeighNa定位是量化交易平台,提供从交易API对接到策略自动交易的完整解决方案,对接了国内外诸多不同类型的金融市场:证券、期货、期权、外汇、数字货币等。有回测功能,但支持较弱。

安装

对windows支持较好,提供了python发行版,其内置了最新版的VeighNa框架以及VeighNa Station量化管理平台,无需手动安装。 对ubuntu支持其次,对mac支持最弱。

安装后,在VeighNa社区论坛注册获得VeighNa Station账号密码(论坛账号密码即是)

Mac安装: bash install_osx.sh

mac在开始安装vn.py之前,需要先手动安装几个特殊的库,打开Terminal后执行以下命令:

1
2
brew install ta-lib  // 不安装这个,会提示talib/_ta_lib.c:601:10: fatal error: 'ta-lib/ta_defs.h' file not found
pip install TA-Lib

talib,是Technical Analysis Library的简称,是一种广泛用在程序化交易中进行金融市场数据的技术分析的函数库。它提供了多种技术分析的函数,方便我们量化投资中编程工作

因为mac上不支持ctp接口,所以要注释掉ctp接口,否则运行会报错

代码框架介绍

vnpy 之前几乎所有代码都在 https://github.com/vnpy/vnpy 这个代码库中,但python很容易造成依赖包冲突,导致软件不能正常工作,从2.x某个版本起,vnpy开始分拆成N个代码库,好处是你只需要安装你需要的依赖,不容易造成依赖包冲突,不好的是拆的太细代码库太多了,维护起来较麻烦。

下面按如下顺序对vn.py各个功能进行说明:数据、存储、交易、回测、rpc、event、策略。

  1. 对接各类数据服务的适配器接口

Demo: 从rqdata获取历史行情,操作步骤:
1) 初始化rqdataClient
2) 构造请求对象
3) 从rqdata获取数据
4) 将数据保存到本地数据库

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
from vnpy.trader.rqdata import RqdataClient
from vnpy.trader.object import HistoryRequest

# 初始化rqdataClient
rqdata_client = RqdataClient()
rqdata_client.init()

# 构造请求对象
history_req = HistoryRequest(
symbol='C2105',
exchange=Exchange('DCE'),
start=datetime(2021,1,1),
end=datetime(2021,2,1),
interval=Interval.DAILY
)

# 从rqdata获取数据
ret_data = rqdata_client.query_history(history_req)

#将数据保存到本地数据库
database_manager.save_bar_data(ret_data)
  • data_manager:历史数据管理模块,通过树形目录查看数据库中已有的数据概况,选择任意时间段数据查看字段细节,支持CSV文件的数据导入和导出。
    一句话概括:用好database_manager这个对象,提供了如下方法:

    1
    2
    3
    4
    5
    def load_bar_data( self, symbol: str, exchange: Exchange,  interval: Interval,  start: datetime, end: datetime) -> List[BarData]
    def load_tick_data(self, symbol: str, exchange: Exchange, start: datetime, end: datetime ) -> List[TickData]:
    def get_bar_overview(self) -> List[BarOverview]
    def delete_bar_data( self, symbol: str, exchange: Exchange, interval: Interval ) -> int:
    def delete_tick_data(self, symbol: str, exchange: Exchange ) -> int:
  • data_recorder:行情记录模块,基于图形界面进行配置,根据需求实时录制Tick或者K线行情到数据库中,用于策略回测或者实盘初始化

  1. 对接各类数据库的适配器接口
    在量化中,研究策略和实盘交易,都离不开数据。如果要提升回测速度,那么就需要搭建本地数据库。
    vn.py数据库结构:DbBarData表示K线数据表映射对象,对应数据库的db_bar_data集合;DbTickData表示TICK数据表映射对象,对应对应数据库的db_tick_data; DbBarOverview表示K线汇总数据表映射对象,对应数据库的db_bar_overview。
    通过对象database_manager实现,该对象通过抽象工厂模式,根据实际情况调用具体的数据库实现类。相关类: BaseDatabase。 存入数据库database_manager.save_bar_data(bars);从csv导入,import_data_from_csv, output_data_to_csv;从RQData查询, download_bar_data。

–基于peewee开发的SQLite数据库接口,无需另外安装配置数据库软件。SqliteDatabase类继承自BaseDatabase

  • 对接mysql–基于peewee开发的MySQL数据库接口。MysqlDatabase类继承自BaseDatabase

  • 对接mongodb–基于pymongo开发的MongoDB数据库接口

  1. vnpy.gateway覆盖国内外所有交易品种的交易接口
    对应接口交易接口Gateway类的query_history函数,实现历史数据的下载
  • 对接futu–基于futu-api开发的富途证券港股、美股交易接口。使用时需要注意本接口只支持限价单。FutuGateway类继承自BaseGateway。参考futu api文档。适用于港美股、期权等

  • 对接ib–封装InteractiveBrokers交易接口,connect, close, subscribe, send_order, query_account, query_position, query_history,底层使用EClient接口。适用于全球证券、期货、期权、贵金属等

  • 对接ctp–基于CTP期货版的6.5.1接口封装开发,接口中自带的是【穿透式实盘环境】的dll文件。适用于国内期货、期权

  • 对接中泰XTP–适用于国内证券(A股)、ETF期权

  • RPC服务(rpc):跨进程通讯接口,用于分布式架构。 使用zmq进行消息传递

  1. 回测
  • cta_backtester:CTA策略回测模块,无需使用Jupyter Notebook,直接使用图形界面直接进行策略回测分析、参数优化等相关工作
    1
    2
    3
    4
    5
    6
    backtester_engine.start_downloading(
    vt_symbol,
    interval,
    start,
    end
    )
    BacktesterEngine 封装了BacktestingEngine,还有init_rqdata。ib有query_history(),futu, tiger没有该接口
  1. rpc & webtrader
  • web_trader:Web服务模块,针对B-S架构需求设计,实现了提供主动函数调用(REST)和被动数据推送(Websocket)的Web服务器

  • rpc_service:RPC服务模块,允许将某一进程启动为服务端,作为统一的行情和交易路由通道,允许多客户端同时连接,实现多进程分布式系统

  1. 事件驱动引擎
  • event作为事件驱动型交易程序的核心,使用Queue和Timer来实现
  1. 开箱即用的各类量化策略交易应用(app):
  • cta_strategy:CTA策略引擎模块,在保持易用性的同时,允许用户针对CTA类策略运行过程中委托的报撤行为进行细粒度控制(降低交易滑点、实现高频策略)

  • spread_trading:价差交易模块,支持自定义价差,实时计算价差行情和持仓,支持半自动价差算法交易以及全自动价差策略交易两种模式

  • option_master:期权交易模块,针对国内期权市场设计,支持多种期权定价模型、隐含波动率曲面计算、希腊值风险跟踪等功能

  • portfolio_strategy:组合策略模块,面向同时交易多合约的量化策略(Alpha、期权套利等),提供历史数据回测和实盘自动交易功能

  • algo_trading:算法交易模块,提供多种常用的智能交易算法:TWAP、Sniper、Iceberg、BestLimit等

  • script_trader:脚本策略模块,针对多标的组合类交易策略设计,同时也可以直接在命令行中实现REPL指令形式的交易,不支持回测功能

  • paper_account:本地仿真模块,纯本地化实现的仿真模拟交易功能,基于交易接口获取的实时行情进行委托撮合,提供委托成交推送以及持仓记录

  • chart_wizard:K线图表模块,基于RQData数据服务(期货)或者交易接口获取历史数据,并结合Tick推送显示实时行情变化

  • portfolio_manager:交易组合管理模块,以独立的策略交易组合(子账户)为基础,提供委托成交记录管理、交易仓位自动跟踪以及每日盈亏实时统计功能

  • excel_rtd:Excel RTD(Real Time Data)实时数据服务,基于pyxll模块实现在Excel中获取各类数据(行情、合约、持仓等)的实时推送更新

  • risk_manager:风险管理模块,提供包括交易流控、下单数量、活动委托、撤单总数等规则的统计和限制,有效实现前端风控功能

交流

我发文章的几个地方,欢迎大家在朋友圈等地方分享,多多交流。

参考

简介

  • Tkinter – Tcl/Tk的python接口,python标准库自带不需单独安装。但界面相对简陋,基础组件不全,框架功能相对较弱,使用不多
  • wxPython – wxWidgets的python封装接口
  • PySimpleGUI – 对tkinter, Qt, WxPython等python gui框架的进一步封装
  • PyQt – Riverbank Computing公司发布的对QT框架的python封装,GPL授权
  • PySide – QT官方发布的QT python封装,LGPL授权,可以闭源发布。 qt官方给出的Pyside和PyQt差异,除了包名、工具名外,大部分差别不大

从目前使用情况来看,PyQt使用的比较多,但PyQt是GPL授权,而PySide是LGPL授权,其功能与PyQt区别不大,但可以闭源发布。量化软件vnpy最新版使用的就是pyside6,下文主要介绍pyside6。

pyside6介绍

  1. 安装
    安装前提:Python 3.6+。使用venv或conda创建一个新的python环境。
    1
    2
    conda create -n qt python=3.8
    conda activate qt
    or
    1
    2
    python -m venv pyside
    source pyside/bin/activate
    然后使用pip安装pyside6
    1
    2
    pip install pyside6 # 安装最新版本
    pip install pyside6==6.0 # 安装6.0版本
    测试安装是否成功
    1
    2
    3
    4
    5
    >>> import PySide6.QtCore
    >>> print(PySide6.__version__)
    6.2.1
    >>> print(PySide6.QtCore.__version__)
    6.2.1
    除了pyside6 lib库安装好外,还安装了pyside6-designer、pyside6-uic、pyside6-rcc等工具。
  • pyside6-uic: 从.ui文件生成python代码,pyside6-uic -i form.ui -o ui_form.py
  • pyside6-rcc: 从.qrc文件生成python代码,pyside6-rcc -i resources.qrc -o rc_resources.py
  • pyside6-designer: Qt Designer对应的命令行程序,用于编辑/创建.ui文件
  1. hello qt程序
    将下列代码保存为hello_py.py,在终端运行python hello_py.py即可。
    1
    2
    3
    4
    5
    6
    7
    import sys
    from PySide6.QtWidgets import QApplication, QLabel

    app = QApplication(sys.argv)
    label = QLabel("Hello Qt for Python!")
    label.show()
    app.exec()
    说明:
  • QLabel是一个可以展示文本和图片的组件,文本可以是普通文本或富文本,比如html
  • QApplication app.exec()进入Qt主循环并且开始执行Qt代码
  1. 开发环境
  • vs code安装插件:Qt for Python
  • qt creator
  • pycharm配置外部工具
  1. 核心概念
  • Qt包括很多组件和模块,比如qtbase是一个包含很多模块的基础组件,它包含的module有:QtCore, QtGui, QtWidgets, QtNetwork等。所有这些module包含了很多你可以直接使用的类,比如QtCore里面包含了QFile, QTime, QByteArray等类。

  • QtWidgets是一个提供了很多预定义Widgets的模块,这些Widgets你可以添加到图形应用程序里面,包括Buttons, Labels, Boxes, Menus等。

  • QML提供了另外一种不同于Widgets的创建用户界面的方法,它首先的动机是应用于移动应用开发,但也可以在桌面应用开发中使用。QML跟Qt Quick模块一起,提供了使用点击、拖放、动画、过渡等与移动设备交互的方式。你可以在QML/Quick应用中找到的元素都聚焦于提供更现代的应用中

Qt基本模块有三部分:

  • QtCore: 提供了核心的非GUI功能,比如signal和slots,properties,序列化等
  • QtGui: 在GUI功能上扩展了QtCore的功能,比如:Events, windows and screens, OpenGL and raster-based 2D绘图,还有图片
  • QtWidgets: 提供了现成的组件,包括UI的图形元素

QML and Qt Quick使用这些模块从python跟QML语言交互

  • QtQML: 跟模块交互的基础python api
  • QtQuick: 在Qt应用中提供了类嵌入Qt Quick
  • QtQuickWidgets: 在基于widget的应用中提供了QQuickWidget类来前乳Qt Quick
  • Shiboken模块:使用python来扩展Qt/C++ 应用
  1. Qt Widgets:
  • signals and slots: 用于QObject对象之间的通信。按钮点击时,click就是信号,槽位是当按钮被点击时发生的事情,比如关闭窗口,保存文件等。类似于其他的callback回调,但回调不是很自然
  • 所有继承自QObject或它的子类的类(比如QWidget)都可以包含信号和槽位。当对象改变状态,且这个状态其他对象感兴趣时,对象可以发出信号
  • 槽位可以用于接收信号,但他们也是普通成员函数。就像一个对象不知道是否有对象接收了它的信号一样,一个槽位也不知道是否有信号连接到它了。这确保了可以用Qt来创建真正独立的组件
  • 一个槽位可以连接任意多的信号,一个信号也可以连接到任意多的槽位。连接一个信号到另外一个信号也是可能的
  • Qt widgets有许多预定义的信号和槽位,你可以创建继承自PySide6 widgets的任何类
  • Qt 自带的layout-support功能可以帮你在应用程序中组织widgets。QVBoxLayout用于垂直布局widgets,QTableWidget用于以表格形式展示信息, QTreeWidget,QTreeView用树的形式展示信息
  1. 使用ui文件
  • Qt Designer时一个图形UI设计工具,可以使用 Qt Designer基于Qt Widgets创建图形界面,它作为一个单独程序pyside6-designer或者嵌入到Qt Creator IDE。Using Qt Designer.设计存储在.ui文件中,是基于XML格式的文档. 可以使用pyside6-uic在编译时将设计转换成python/c++代码。

  • 可以使用QtUiTools模块里面的类来直接加载ui文件

  • 从Designer或QtCreator用QUiLoader和pyside6-uic使用.ui文件

  1. 其他功能
  • Using .qrc Files (pyside6-rcc) – Qt资源系统是一个可以用来在应用程序中存储二进制文件的机制,这些文件可以嵌入到应用程序并且可以被QFile类和QIcon、QPixmap类的构造函数来访问,文件名用:/来开始。最常见的使用情况时自定义的图片、图标、字体等

  • Qt Linguist和它相关的工具可以用来提供应用程序多语言的翻译功能,参考Translating Applications

  • Qt Widgets应用使用一个依赖于底层平台的默认主题。在某些情况,存在一些系统范围的配置可以用来修改Qt主题,也可以自己的widgets并为每个组件提供一个自定义的style. 参考Styling the Widgets Application

  • QML是一个声明式语言,可以让你比传统语言(c++)更快的开发应用程序。由于它的声明特性,非常适合设计应用程序的UI。在QML,一个用户界面被指定为带有属性的对象树

  • 一个PySide6/QML应用程序由至少2个不同的文件组成–一个是QML描述的用户界面文件,另外一个是用于load QML文件的python文件。QtQml和QtQuick模块提供了基于QML的UI的必要功能

  • Shiboken 擅长Qt相关的binding生成,这意味着任何Qt/C++项目可以很容易暴露给python。另外,Shiboken也提供了对于非Qt的c++项目的支持

进阶

交流

我发文章的几个地方,欢迎大家在朋友圈等地方分享,多多交流。

参考

Latex 是功能非常强大的排版工具,MacTeX 2021有4Gb 大小,之前装过觉得用处不大,这次决定装一个mini版本BasicTex,不用gui的话,功能也够用了

安装basictex

BasicTex 官网手动下载pkg文件手动安装。或者使用homebrew安装。

使用 homebrew 安装非常简单,只需一条命令即可。

$brew install basictex
安装完还不能直接使用,还需要把 texlive 添加到环境变量中,才能找到相关的命令。

$export PATH=/usr/local/texlive/2021basic/bin/universal-darwin/:$PATH
执行$xelatex不报错的话,说明环境安装成功。
然后就是安装相关的包,以及更新包。

sudo tlmgr update --self
安装包的时候速度慢的话推荐使用清华的CTAN 镜像

使用basictex生成简历

首先到网上找到喜欢的模板。比如: billryan/resumexdanaux/moderncv

以billryan/resume 为例,git clone下载到本地后,使用git switch zh_CN 切换到中文分支。

执行: $xelatex resume-zh_CN.tex

编译失败,会提示缺少某些包。使用tlmgr安装对应的包即可。

比如: $sudo tlmgr install xifthen ifmtarg titlesec enumitem nth

安装完成后,继续xelatex编译即可,会生成resume-zh_CN.pdf 文件。

如果只是偶尔使用一下xelatex,也可以考虑试下xelatex云编译器 cloud compiler LaTeX to PDF

交流

我发文章的几个地方,欢迎大家在朋友圈等地方分享,多多交流。