当前位置: 首页 > 工具软件 > ADBS > 使用案例 >

Python 算法交易实验58 ADBS:QuantData到MyQuantBase-续

卜瀚漠
2023-12-01

说明

上一次碰到了时间轴的前置问题,篇幅拉的太长,所以这篇继续完成MyQuantBase的取数加工问题。说起来,时间轴的使用计划由来已久,现在只是开始正式的去使用。关于时间轴,可能还有一些概念需要补充。

内容

1 时间轴的使用

观察时间点(Watch Point): 当我们要开始分析和决策时,首先会站在某个时间点,或者说时隙(Time Slot)。 按我的体系设计,都是以分钟作为时隙的,这样考虑到了计算机硬件的承载,也兼顾人的使用习惯。

数据时间点(Data Point): 记录、汇总了某个时隙的数据。

时间轴默认随着自然的时间不断延展的,连续的有序时隙;对于交易来说,因为划定了一些特定的时间用于交易,所以交易时间轴是由若干连续的有序时隙组成的。

机制:在不明确哪些时间是合法的交易时隙时,我通过在自然时间轴(全集)上发起请求,查询并记录新增的交易时隙。

现在有一个全局性的问题:假设未来会扩展100个不同维度的实时数据,主程序(当前程序)是否可以利用到所有的数据?

假设有3个时隙, t1, t2, t3。

在t2时,所有程序都在运行关于t1时隙的维度数据存储/计算。如果某个程序基于完整的数据作出决策,那么在t2时就有风险。因为有些程序可能会在t2的后几秒完成t1的落库,如果主程序恰好处于前几秒的话就读不到。

如果一定要在t2决策,那么就要将时隙分为节拍(di-da)。所有程序在di节拍(前30秒)必须完成数据的准备,在da节拍(后30秒)决策。

简单起见,我们仍然维持一个时隙的假设:即每个处理程序,必须在一分钟内完成所有的工作,也就是把t1的结果落库。

所以要安全的访问到所有的t1,就必须在t3时刻。也就是说,在工程中,观察点不是紧挨着数据点,而是间隔了一个时隙的。这样就能从机制上确保同步,每个处理一分钟的限制在绝大多数情况下是可行的(可以做到足够复杂的处理)。

在量化实操中,本来也引入了“冷静时间”(Calm Down)的概念,以防止分钟级噪声数据。一般采取冷静10分钟的操作,所以观察时间后挪一分钟影响是很小的。

以上是关于时间轴设计的一些通用性补充,对于本应用而言。

  • 1 当前时刻为t2,交易时间轴最多只是到t2-1的
  • 2 t2有可能不是交易时刻
  • 3 约定:当t2-1处于交易时间轴时,可以进行特征计算
  • 4 按照约定,那么每天15:01分会观察15:00(及之前)的数据;9:31分会观察9:30(及之前的数据)
  • 5 对于历史数据而言,也采取同样的规则符合 t2-1 在时间轴内的才可以计算

2 Worker

Worker以后要专门做文档了,属于逻辑类产品(ADBS属于流程类产品)

Worker的处理流程主要分为两块,一块是流程类的,通常命名为worker00_xxx.py。这个流程负责从队列中取数,然后调用具体的Worker进行处理(通常命名为 XXX_Worker.py)。

具体的业务逻辑就不说了,我觉得一些流程间衔接的细节是我关注的。Worker部分本身的基础已经确认其核心结构是灵活及可靠的(关于其使用性可以在后续再不断强化),关于量化的处理本身也是相对固定的。

Worker在具体执行上,分为两类,一类是随ADBS默认执行的,采用非分发模式。这样当一些Worker分身因为故障失效,认领的消息最终会被处理掉。

另一类是采用分发模式运行的。目前常用的是限量Worker( CNT_Worker), 这类Worker会不进行等待,持续执行,直到次数耗尽。未来还可以增加限时Worker, 运行直到某个时刻为止。

本次实施后,可以认为服务总是会将实时数据进行处理(从而确保了实时反馈)

3 整体流程

从架构上,就分为流程性问题和逻辑型问题

  • 1 配置文件

    • 1 修改目标服务器名称和项目名称(库名称)
    • 2 修改sniffer的执行周期(一般10秒)
    • 3 monitor要使用的redis变量名称(每个项目必然不同)
    • 4 sniffer的redis var
  • 1 sniffer

    • 1 时隙同步。通过和mymeta集群以及redis进行更新,并使用本地pickle文件来减少与数据库的交互。 - 目前redis_var直接写在程序体,下次ADBS迭代时可以更新到配置文件中定义,程序导入
    • 2 取数停等。在向数据源取数之前,先根据单次取数的最大数量与当前队里的数量进行比较,不溢出才进行取数。顺序不能乱。
    • 3 唯一Sniffer。取数本身是低CPU、高IO操作,所以约定只有一个Sniffer进行取数,这样就避免了取数协调。
    • 4 从Mongo取数与应答分成了两步(省了取数时应答这一步)
  • 2 app

    • 1 数值类型转换。在使用redis时(大概是我设计时的问题),所有的数据都转为了字符型,所以在app01、app03处理时(存Mongo),要约定转换的数值列。【类型定义】未来在整体的设计中,在应用上将数据类型规范为数值型和字符型两类。(更底层的设计的确是全部是纯字符,然后由程序推断)

    • 2 app01中直接声明了monitor使用的redis var,未来应当统一在配置中声明。

  • 3 worker

    • 1 默认worker。默认的worker随ADBS启动,采用非分发方式,处理的频度和量级低。主要是解决在分发状态下可以漏掉的数据。
    • 2 CNT Worker。是针对累积量大时启动的worker,执行后自动删除。使用分发方式处理。
    • 3 worker中的分发方式字段,还是应当使用一个命令行参数控制。一般来说,命令行应当包括模式(并发/非并发)以及强制两类字段。特别是为了减少无谓的吞吐,有时候会使用基于缓存的计算。当调试或者出错时,我们需要通过强制方法归位。
  • 4 monitor

    • monitor03里的redis var是写死的,之后也应当放在配置文件里定义。

其他

执行效率方面

下一步应该把nginx这块搭起来,目前的数据库代理服务只能用单核(异步)方式,用多核会有一些奇怪的问题。因为每时隙在计算指标时,都会发起一次数据库请求,所以开销比较大。(这里一个小的思维关键点:是采用pandas载入内存批次计算好,还是按分钟逐次IO计算好? – 在小型、校验、一次性的处理中,用pandas比较好;但是在进行大规模、生产式计算时,后者比较好。唯一比较耗的就是磁盘,而磁盘的速度越来越快、容量越来越大、价格越来越便宜)

本来与nginx相关的还有ssl证书问题,我觉得用一年免费的太麻烦了,打算做个10年的自签名证书。这里就又需要解决服务器、浏览器的鉴权问题。

简单起见,先不考虑ssl问题,仅考虑负载均衡,先做一个算网内的多agent分摊。

程序设计方面

基于全局性质的参数place_holder。有些参数可能在当前场景下不需要特殊声明,但是考虑到通用场景(算网),那么应该将参数都抽出来单独复制。

 类似资料: