Python 算法交易实验60 ADBS: MyQuantBaseStep1Signals

说明

我发现从MyQuantBase 并不能直接到 MyQuantBaseStep2Signals,主要是因为后者需要依靠一阶的斜率计算。这部分本来也可以放在MyQuantBase做,但是ADBS又做了一次升级,所以干脆独立一个ADBS,与MyQuantBase同级,都会向QuantData取数。

之后还要解决基于同样数据,但是增添新的计算逻辑(并行)的结构。

内容

1 概念

全ADBS与半ADBS。全ADBS是最初的结构,从数据入Mongo,到Mongo到工作队列,以及工作队列到出Mongo这样一个完整的链条。一个项目至少会有一个全ADBS。

半ADBS是为了在兼顾稳定性的情况下,拓展逻辑处理的灵活性下的结构。半ADBS没有自己的MongoIn, 也没有入系统队列(也就没有app01)。

半ADBS又需要在监控中表示入系统的进度,所以在监控的数据方面,半ADBS需要“借用”某个全ADBS的缓存变量。

全ADBS通常无需管理通道(只用默认的1个),但是半ADBS会使用不同的通道。

在本次需求中,构造一个全ADBS就可以,相对比较省事;但是在下一次,例如要变换周期时,肯定就会涉及半ADBS。

在这个过程中,还有一个关于设计方面的想法。

本来还有一种方案,是修改全ADBS的结构,在里面允许多个工作队列。但这样就属于「用复杂方法解决复杂问题」,性价比是极低的。而半ADBS则是用简单方法/结构解决复杂问题,性价比就高得多。简单结构的特点总是看起来存在一些冗余,例如半ADBS会有自己的数据库,每加一个半ADBS就多一个库。但是简单结构的叠加(甚至删除)都是很灵活,可靠的。

2 构造

MyQuantBase从QuantData取数,而新的ADBS(MyQuantBaseStep1Signals)也要从QuantData里取数,所以:

  • 1 给QuantData的MongoOut部分增加一个通道(索引)
  • 2 创建新的项目,sniffer部分同 MyQuantBase,但是要注意修改通道
  • 3 修改配置,这次使用MongoAgent负载均衡组(LBG)

2.1 QuantData.Mongo.Out加索引

到QuantData项目下,导入init_projects.py的依赖

执行一下语句,建立一个新的通道

cur_w.set_a_index(tier1 =project_name, tier2 =step1_mongo_out, idx_var='_ch002')

2.2 创建新的ADBS

  • 1 修改项目名称configs_base.py
  • 2 切入容器,执行 init_projects_base.py(挂载新的)
  • 3 增加并修改sniffer
    • 本次引入了全局redis变量配置
    • 取消再次写入时间轴(MyQuantBase已经在做)

这样流程就完毕了,接下来就进入Worker部分

修改核心部分的处理逻辑,并将结果进行标准化挂接


            for T in T_list:
                res_dict['close_T_%s_K' % T] = cal_K(recs_df2['close']) 

worker_af = af
worker_Chain_session_list = Step1Chain_session_list
worker_Chain_session_dict = Step1Chain_session_dict

在配置文件部分,要记得修改数值型变量的声明

# 数值型转换(如果声明的变量缺少流程就会中断)
app01_toDoubleVarList = ['open', 'close', 'high', 'low', 'vol', 'amt','data_slot']
app03_toDoubleVarList = app01_toDoubleVarList +['close_T_600_K','close_T_2400_K'] 

运行监控

运行结果
Python 算法交易实验60 ADBS: MyQuantBaseStep1Signals_第1张图片

2.3 运行方式

启动一个 -d 服务,用于执行各种基础流转。

python3 sche.py

按次消耗的worker,通常用于冷启动,或者任务有堆积的时候。

python3 CNT_worker.py

有四个参数可以选,通常来说会修改 cnt_limit或者worker_name;有时会修改is_fetch_mode。

序号 参数 作用
1 cnt_limit 执行次数,默认10000
2 is_fetch_mode 任务模式,默认yes,分发
3 worker_name worker名字,默认alice
4 group_name 工作组,默认group1

因为现在数据库的代理通过负载均衡增强了(10倍),所以现在可以多启动一些worker。不过看起来瓶颈可能会出现在mongo,因为我当时只给了8g内存。不过至少目前来说是够用的,未来如果有更大规模的存储吞吐时可以扩充为局域网的mongo集群。

按带宽消耗worker,用于增强实时的处理能力

python3 Band_worker.py

对应的参数控制如下

序号 参数 作用
1 to_dt 执行时间上限,默认’2099-01-01 00:00:00’
2 pace 休眠时间上限,默认为1,如果<=0,那么就不休眠
3 is_fetch_mode 同CNT_worker
4 worker_name 默认alice
5 group_name 默认group1

3 层级

本次做到这里,就生成了第一步的特征提取。我发现每一层的ADBS对应着原来pandas里的每次rolling或者diff,所以这种时序的计算的确是比较麻烦的。

pandas虽然方便,但每次只能探索一个假设空间,而且不能持久和自动化。

例如,我在1月1日探索一个周期 T1觉得没啥用,但是在3月1日觉得说不定有点用,但是就很难立即验证,通常就会放弃。又或者我想知道此时此刻,某个空间下的信号是否会发出,如果要重新拉取数据,打开程序计算就很麻烦。

我想,ADBS的意义就在于将假设空间持久化,计算自动化,无论在什么时候,只要进行一次数据库查询就能获得可能需要准备数分钟乃至数十分钟的数据。

当然,也包括提供实时的信号。

如果退一步,假设没有pandas这样的分析工具,我发现其实时序上的处理还是比较麻烦的。最大的点在于逻辑的深度的确比较有挑战。

以本次要实现的信号组为例:

  • 第一层:原始数据层 ,open, close这些
  • 第二层:L1特征层。一些是例如open_ma_600这样的滑动平均,通用性比较强。还有一些是像这次计算的斜率K。
  • 第三层:L2特征层。基于上一层的数据进行计算,例如对于斜率K进行差分(本次只是一阶,但可以拓展为多阶)。
  • 第四层:L3特征层。基于K的差分再进行滑动统计,形成一些周期统计。在这一层可以形成本次的信号。
  • 第五层:L1决策层。采用之前各层的数据,进行增强决策。
  • 第六层:L2决策层。基于L1决策层的基础,再进行过程决策。
  • 第七层:交易层。基于决策层的结果,发起候选交易。

这里实现的只是一个简单的版本(尚且那么多层级),我觉得逻辑的复杂度已经达到一个人(大部分人)单次任务的极限了。

如果保持结构不变,那么每一层可拓展的维度还非常多,这样就可以在更多的空间上决策。当然也可以继续保持特征的深度探索和决策的深度探索,结构还可以不断的扩充,层级也会不断的变多。

其实仅仅是这样一个基础的结构,其能够发现的特征就已经超过人能够理解的范围了,暂时我觉得是够用的。

其他

  • 1 在制作镜像的时候,修改的内容直接在里面rm、vim去修改,挂载的文件是临时的,commit的时候不会将对应的数据更改提交(但是会把名称传上)
  • 2 总体来说,本次的升级还是比较平滑的,会省掉之后很多次的重新挂载(主要是要手工编辑一些有规律的变量),只要在配置文件里说明就好了。

新的启动项只挂载了配置、初始化程序、取数程序以及核心的Worker处理逻辑。

docker run -d \
 --name=Shard_MyQuantBaseStep1Signals_CNT_Worker_16 \
 --rm \
 -v /etc/localtime:/etc/localtime  \
 -v /etc/timezone:/etc/timezone\
 -v /etc/hostname:/etc/hostname\
 -e "LANG=C.UTF-8" \
 -v /PATH/configs_base.py:/workspace/configs_base.py \
 -v /PATH/init_projects_base.py:/workspace/init_projects_base.py \
 -v /PATH/sniffer.py:/workspace/sniffer.py \
 -v /PATH/sniffer01_query_quant_data.py:/workspace/sniffer01_query_quant_data.py \
 -v /PATH/Step1Worker.py:/workspace/TheWorker.py \
 registry.cn-hangzhou.aliyuncs.com/andy08008/apifunc_database_model1:v4 \
 sh -c "python3 CNT_worker.py --cnt_limit=50000"
  • 3 任务的(重新)初始化

刚开始调试时,可能因为数值型变量没有转换等问题,会导致原始数据中存在天然的计算错误,所以可能要进行源的任务通道初始化。这样数据再次入库时会自动转成数值型

数据重新入库后,在本系统内再次将数据的状态初始化,这样就会重新走任务队列的流。

  • 4 更大的计算量、存储量来解放设计者的时间

最近的大语言模型证明了一件事:计算机硬件的发展,允许人们以更“傻”的方式来堆叠,达到更高的效果。

过去受限于计算机硬件资源,程序设计者总是想办法用更巧妙的方法来计算和存储。例如pandas里的rolling,可以将n个周期的数据一次载入,批次计算再输出。而现在我的方法则是利用更大、更快的存储加上分布式网络进行更“傻”的计算。只要设计好一次的计算,例如载入100个数,求平均,这显然比rolling要简单不知道多少。(rolling的背后涉及到并行计算,大概转成了矩阵之类的)

所以,数据的处理可以做的非常精细,只要考虑“做好一次”即可。效率的问题通过机器堆,在人的应用层面上感受不到差别(当然机器更累一些)。

这样,给到更多的硬件(这个假设看起来越来越成立),我们通过简单的结构就可以堆叠更大(并行),以及更复杂(存储多个空间)的项目与方法。

你可能感兴趣的:(算法交易,python,算法,数据库)