即使是Quant Researcher, 写一手高质量的代码也是非常重要的。再好的思路,如果不能正确地实现,都是没有意义的。
写一手高质量的代码的意义,对Quant developer来讲就更是自不待言了。这篇笔记就介绍一些python best practice。
始终为策略研究创建独立的虚拟环境
在量化研究中,很多功能会借助第三方包。第三方包也必然会依赖其它第三方包。如果有两个以上的包都依赖于某一个包,但是要求的版本不同,这就发生了依赖地狱。有一些量化研究员常常会把自己的研究环境搞坏,就是因为不断尝试新的技术、新的python库,而这些新的库,依赖的第三方版本和原来的发生冲突,强行覆盖之后,导致之前的python库无法使用造成的。
解决依赖地狱问题,需要在不同的层面上进行解决。首先,我们可以通过 conda来为每一次新的策略研究项目,构建一个独立的虚拟环境,即使我们是使用jupyter notebook进行策略研究的,也是如此。
有点软件工程意识的研究员会使用requirements.txt来管理依赖库。但这样仍然是错误的。我们应该使用poetry来管理依赖库。poetry的作用是,当我们通过poetry往项目中增加依赖时,它能告诉我们,新增加的库是否与已有的库相冲突。它还有可能自动帮我们找到彼此兼容的版本。
因此,新策略研究的正确打开方式是:
conda create -n new_project python=3.11
poetry init
poetry add pandas^2.0
poetry add scipy^1.8
pandas和scipy都会依赖numpy。当我们先加入pandas2.0时,它会确定一个numpy版本,随后加入scipy1.8时,此时poetry就会看scipy声明依赖的numpy版本,是否与pandas声明的版本中存在共同兼容的版本。如果找到,则添加成功,否则,poetry将提示我们,重新选择恰当的版本
如此一来,就不会无声无息地失败了。Poetry就像乐队指挥一样,能够帮我们精确地管理各种依赖关系,避免冲突。
书写漂亮的代码
在写代码时,我们会有自己的风格。比如变量名如何使用大小写,单词之间如何分隔,如何使用空格和缩进等等。为了统一风格,Python社区有一个统一规范,称为PEP8。
强制我们的代码遵循PEP8的最佳方式,是使用black作为代码格式化工具。
推荐black的原因是,它基本上不接受定制。实际上,代码风格的定制几乎没有意义。一个人即使长得丑点,你强迫自己多看他几眼,就会发现其实也是能看的。
black的成功就在这地方,它的motto是不妥协的格式化工具。很多事情就是这样,坚持自己的风格,宁可站着死,不愿跪着生,向死而生,反倒是机会。
使用语法检查工具
有很多错误可以在测试之前就找到,这样除错成本最低。如果你是使用Pycharm或者vscode这样的IDE来进行开发,就能随时用上IDE提供的语法检查功能。
很多策略研究员会使用notebook进行探索式开发。现在,我们在vscode中也能写notebook了。在vscode中使用notebook,会比浏览器中使用具有更多的优点,比如:
- 它能记住多个编辑插入点,因此我们可以方便地前后跳转。在浏览器中打开的notebook中,要做到这一点,只有一个办法,就是插入标题,通过outline来进行导航跳转。
- 语法检查和自动完成。这正是这一节我们提到的功能。
- 单元格调试。这点更是比浏览器中的notebook要强不少。Farewell to print!
单元测试:Fake it till you make it!
就连很多正牌的程序员也做不好单元测试。但是这一点非常重要。作为策略研究员,我们并不需要对所有的代码都执行单元测试,但是,如果你创造了一个可复用的轮子,你就应该提供单元测试报告。
测试的意义是, testing leads to failure, failure leads to understand。我喜欢这句话。在我们的量化课程中,我们也掺杂了一些故意让你失败的例子。只有这样,你才会对系统是如何运作的有深刻的理解。在回测中表现得很好的策略,也能在实战中有好的表现。
我们可以使用pytest框架来编写单元测试,它非常轻量易用,大约半天的时间就足够入门了。
单元测试并不复杂,主要难点在于如何将待测试的代码与系统中的其它部分隔离开来。再花上两三个小时,学一下mock的使用,熟练之后,你甚至会爱上单元测试。
如果你在策略研发中,也遇到过环境构建、代码质量不高等问题,可以抽空看看这本书,它的电子版是免费的: