发布于vn.py社区公众号【vnpy-community】
 

原文作者:张国平 | 发布时间: 2020-01-26
 

cProfile介绍

 

较为大型的程序在开发完成后,通常都会采用以下步骤来进行性能优化:

  1. 对代码的执行效能测量与分析(profiling);
  2. 找出程序执行耗时中的瓶颈所在;
  3. 针对少数关键的热点代码进行优化改进;
  4. 提高整体程序的执行速度。
     

在Python中如果要进行计算机程序执行效率的分析,有好几种方式可以使用(具体请参考Python官方手册),而对于大部分用户来说,最常用的方法就是使用cProfile模块。
 

cProfile模块是一个Python标准库内建的分析工具,采用hook进CPython虚拟机的方式,来测量每一个函数运行所花费的时间。尽管hook本身会导致显著的额外开销,但通过这种测量方式我们能获得更多的细节信息,有些甚至能帮助我们在代码的底层执行细节中找到令人惊讶的发现。
 

先来了解下cProfile的输出信息,如下图所示的内容整体可以分成6大类:

  • ncalls:表示函数调用的次数;
  • tottime:表示指定函数的总的运行时间,除掉函数中调用子函数的运行时间;
  • percall:(第一个percall)等于 tottime/ncalls;
  • cumtime:表示该函数及其所有子函数的调用运行的时间,即函数开始调用到返回的时间;
  • percall:(第二个percall)即函数运行一次的平均时间,等于 cumtime/ncalls;
  • filename:lineno(function):每个函数调用的具体信息
     

description

 

使用Jupyter Notebook执行分析

 

第一步是加载相关模块,注意cProfile是Python内置标准库,直接import即可:
 

from datetime import datetime
import cProfile

from vnpy.app.cta_strategy.backtesting import BacktestingEngine, OptimizationSetting
from vnpy.app.cta_strategy.strategies.atr_rsi_strategy import AtrRsiStrategy

 

第二步,定义回测函数,里面需要填入策略回测品种所对应的参数:
 

#%%
def runBacktesting():
    engine = BacktestingEngine()
    engine.set_parameters(
        vt_symbol="IF888.CFFEX",
        interval="1m",
        start=datetime(2010, 1, 1),
        end=datetime(2019, 12, 30),
        rate=0.3/10000,
        slippage=0.2,
        size=300,
        pricetick=0.2,
        capital=1_000_000,
    )
    engine.add_strategy(AtrRsiStrategy, {})
    engine.load_data()
    engine.run_backtesting()
    engine.calculate_result()
    engine.calculate_statistics()
    engine.show_chart()

 

最后,使用cProfile来运行runBacktesting函数,并将输出的内容按照cumtime进行排序:
 

cProfile.run("runBacktesting()", sort="cumulative")

 

性能分析的输出结果如下图所示:
 

description

 

基于gprof2dot的可视化展示

 

尽管我们已经对输出的结果进行了排序处理,但肉眼看起来还是不够直观。比起密密麻麻看得眼睛都疼的一堆数字,还是可视化图表的呈现效果更为清晰,所幸在Python性能分析这块,同样已经有了成熟的工具体系可以实现。
 

安装graphvi

 
graphvi最方便的地方在于能够很快的清晰的画出点与点之间的关系,并且有许多布局算法能够很好的去布局,安装流程如下:

  1. 进入graphvi官网,如果是windows系统,找到对应的msi程序并且点击下载
  2. 安装msi程序,安装完毕后打开文件夹C:\Program Files (x86)\Graphviz2.38\bin,保证能看到文件【dot.ext】;
  3. 在环境变量path中,加入【C:\Program Files (x86)\Graphviz2.38\bin】,保存退出
     

安装gprof2dot

 

执行下面代码,安装gprof2dot。
 

pip install gprof2dot

 

分析生成可视化图表

 

首先需要创建策略回测用的脚本文件run.py,里面的内容整体上和我们在jupyter notebook中使用的回测逻辑类似:
 

from datetime import datetime

from vnpy.app.cta_strategy.backtesting import BacktestingEngine, OptimizationSetting
from vnpy.app.cta_strategy.strategies.atr_rsi_strategy import AtrRsiStrategy

def runBacktesting():
    engine = BacktestingEngine()
    engine.set_parameters(
        vt_symbol="IF888.CFFEX",
        interval="1m",
        start=datetime(2010, 1, 1),
        end=datetime(2019, 12, 30),
        rate=0.3/10000,
        slippage=0.2,
        size=300,
        pricetick=0.2,
        capital=1_000_000,
        )
    engine.add_strategy(AtrRsiStrategy, {})
    engine.load_data()
    engine.run_backtesting()
    engine.calculate_result()
    engine.calculate_statistics()
    engine.show_chart()

if __name__ == '__main__':
    runBacktesting()

 

然后在该文件夹下,按住Shift键点击鼠标右键,选择【在此处打开命令窗口】或者【在此处打开PowerShell】进入命令提示符环境,并运行cProfile进行性能测试:
 

python -m cProfile -o result.out run.py

 

回测完毕后,会将性能分析输出的结果自动写入到result.out文件中,注意该文件是二进制的格式,无法直接查看:
 

description

 

回到命令提示符中(cmd或者Powershell),运行下列命令来使用gpro2dot把result.out转换成png图表:
 

python -m gprof2dot -f pstats result.out | dot -Tpng -o result.png

 

执行完毕后,我们可以看到文件夹内新增了png文件,如下图所示:
 

description

 
打开这个png图片,我们可以清晰地看到每段代码的执行顺序,以及它所消耗的时长比例,这样更易于我们找到不必要的代码开销,从而实现性能优化:
 

description

 

除了本文中使用的分析案例CTA回测功能外,cProfile模块同样可以用于vn.py整体性能方面的优化改进,通过上述流程找出热点函数代码段后,针对其采用更高效的数据容器、改进逻辑算法细节或者使用Numba和Cython等技术来提升数学计算速度等等。
 

 

《vn.py全实战进阶 - 期权零基础入门》课程全新上线,内容专门面向从未接触过期权交易的新手,共计30节课程带你一步步掌握期权的基础知识、了解合约特征和品种细节、学习方向交易和套利组合等各种常用期权交易策略,详细内容请戳新课上线:《期权零基础入门》