一个完善的量化交易系统不但包含了最基本的选股、择时、回测等基本的模块,而且还包含了众多的独立任务模块,这些模块都采用了可插拔的设计方法。本系列文章将会分别讲解几种不同的实现这些任务模块的技术。
定时执行是一种普遍采用的技术,容易理解也方便实现,很多开发框架都为快速的设定定时任务提供了支持。那么接下来我们就来看看实现定时任务的技术手段。
在系统部署时,我们一般采用的Linux的服务器(以CentOS 7为例),有些任务是作为独立的脚本存在的,这时一般是通过Linux系统的crontab服务管理。首先确保cron任务处于启动状态,并且设为开机自启动。
# systemctl start crond # systemctl enable crond
添加一个任务:
# crontab -e 0 * * * MON-FRI python3 /opt/get_k_data.py
上面添加了一条每周一到周五的每个小时执行一次命令“python3 /opt/get_k_data.py”。很明显可以看出来,“0 * * * MON-FRI”这一段是用来指定执行的时间,依次分别为分钟、小时、日、月、星期几。假如上面的任务,我们认为只需要交易时间执行就可以了,那么可以修改为:
5 9-15 * * MON-FRI python3 /opt/get_k_data.py
这样就会在9:05、10:05、11:05、12:05、13:05、14:05和15:05执行。
如果有些定时任务必须跑在Windows下,那么可以采用Windows的Task Scheduler来管理,这是图形化的管理工具,这里不再赘述。
对于集成到平台中的任务,就可以通过开发框架的支持来实现,这里以Spring Framework为例说明。
Spring通过scheduled注解实现定时任务。
@scheduled(cron="0 0-15 * * * MON-FRI") public void doTask(){ //Do something }
这个注解里是cron参数,和Linux的crontab类似,也是指定在某个固定的时间点执行。不过需要特别注意的是,和Linux不同的是,这里的cron是六个参数,分别是“秒、分钟、小时、日期、月、星期几”,多了一个“秒”。
@scheduled(fixedDelay = 30 * 60 * 1000) public void doTask(){ //Do something }
这个注解里的参数fixDelay,它用来指定上一次任务执行结束到下一次任务调用之间的时间差,单位是milliseconds,因此上面的代码表示每次执行完毕后间隔半小时再执行一次doTask。
@scheduled(delay = 30 * 60 * 1000) public void doTask(){ //Do something }
这个注解里的参数delay,它用来指定两次任务调用之间的时间差,单位是milliseconds,因此上面的代码表示每半个小时执行一次doTask。
虽然fixDelay和delay含义不同,可是有时候为了加速执行,我们会把改为并行执行,也就是说doTask中启动相应的线程来实际完成任务执行,那么这种情况下fixDelay和delay就没有太多差别了。
上面只是举了几个简单的例子,更多的使用方式可以参考spring的官方文档。
定时任务使用起来十分方便,可是也存在一些问题。
那么我们应该怎么解决上述问题呢,后面将逐步深入讲解。