从 KDB 服务器拉取 nbbo 数据

Pulling nbbo data from KDB server

我有一个 table 的带有日期、开始时间、结束时间的代码,我需要从服务器上的 nbbo table 中提取 nbbo。例如

Date         starttime    endtime      sym
2014.05.01  15:10:38.000  15:10:58.000 KT
2014.05.01  15:15:53.000  15:16:23.000 IBM
2014.05.01  15:37:39.000  15:37:59.000 AAPL

理想情况下,我将打开一个服务器句柄,并通过传入此 function:getnnbo 并将其称为:getnnbo[KT;2014.05.01;15:10 来提取每一行的数据:38.000; 15:10:58.000]` 其中函数定义为

getnbbo:{[sym;dt;starttime;endtime]:h1"select 0.5*(first bid + first ask) from nbbo where date=",string[dt],",sym =`",string[sym], ",linetime within (",string[starttime],",",string[endtime],")"}

当我将其称为 getnnbo[KT;2014.05.01;15:10:38.000; 时,此函数有效。 15:10:58.000]` 但我不确定如何为 table 中的每一行执行此操作,因为我必须使用服务器的句柄。

假设 lst 是具有 `date`starttime`endtime`sym 列的查找 table 的名称,以下内容应该适合您:

getnbbo ./: flip lst[`sym`date`starttime`endtime]

在上面我们做了以下操作:

  • lst[`sym`date`starttime`endtime] - 以正确的顺序提取列值,以便它们与函数 args
  • 对齐
  • flip lst[...] - 将列值转置为函数的正确形式

关于您粘贴的代码的其他一般要点 --

从右到左求值

从您的 select 声明中提取以下内容:

0.5*(first bid + first ask)

这实际上是按照您的要求进行的,但是是偶然的。它实际上没有正确的范围。 Kdb+ 将从右到左评估这个。所以在上面的形式中它将

  1. 获得第一个问题
  2. 添加bid
  3. 从结果中取第一个值

这是在计算您在这种情况下想要的值,但在不同的情况下可能会误导您。

正确的写法是:

0.5 * first[bid] + first[ask]

这将确保评估的顺序是

  1. 获得第一个ask
  2. 获得第一个bid
  3. 将两者相加
  4. 乘以 0.5

或者,如果您喜欢括号,您可以这样写:

0.5 * (first bid)+(first ask)

字符串生成函数

getnbbo 函数生成字符串形式的查询 - 这对于简单的情况很好,但通常不是好的做法。通常最好将其设为 (1) 带参数的函数或 (2) 切换到函数式 select 语句 - (2) 需要对 Kdb+ 有更深入的了解,我不会在这里深入讨论。

一个直接的改进是使它成为一个接受参数的函数。所以 getnbbo 会变成类似这样的东西:

getnbbo:{[handle;sym;dt;starttime;endtime]
    getDataFunc:{[s;dt;st;et]
        select 0.5*first[bid]+first[ask] from nbbo where date=dt, sym=s, linetime within (st;et)
    };

    handle(getDataFunc;sym;dt;starttime;endtime)
 };

在上面,

  • getnbbo func 接受与之前相同的 args,但我们也传入句柄(不是必需的,但很好的做法)
  • getnbbo 中,我们定义了一个新的参数化函数 getDataFunc,它给定参数 (args) returns select 语句的结果以及适当的子句
  • 最后,它将 getDataFunc 发送到带有输入 args
  • 的远程句柄

进一步阅读:

我建议不要对服务器上的每一行发出请求,而是一次发送完整的 table(如果很大,则发送一部分)并在一次请求中从服务器获取数据。这应该会加快处理速度,因为请求更少,服务器生成结果的时间也会更少,因为通常对列表进行计算比对单个行进行计算要快。

所以你的函数应该像下面这样(只是一个例子)。你可以optimize/modify根据你的需要。我假设您的代码 table 每个 (date;sym) 组合只有一个条目,因此它可以作为主键。

   getData:{[tbl] select 0.5*first[bid]+first[ask] from (nbbo ij `date`sym xkey tbl) where linetime within (st;et) }

然后运行它在服务器上使用服务器句柄。 'tbl' 是您输入的 table 和代码。

   handle(getData;tbl)

ma3266评论后编辑:

我假设以下两个条件:

a) nbbo table 在服务器上分区

b) 您输入的 tbl 具有与 nbbo 中相同的日期和符号列名称。否则,您可以使用 'xcol' 重命名它们。

     getData:{tbl:0!tbl; tempNbbo:0!select from nbbo where date in tbl`date,sym in tbl`sym ; select 0.5*first[bid]+first[ask] from (tempNbbo ij `date`sym xkey tbl) where linetime within (starttime;endtime)}

但如果您的输入 table 包含多个日期的数据,这可能会导致大量内存使用。在这种情况下,您可以使用以下函数按日期中断输入 table。

   getData:{tbl:0!`date xasc tbl; raze { tempNbbo:0!select from nbbo where date in x`date,sym in x`sym ; select 0.5*first[bid]+first[ask] from (tempNbbo ij `date`sym xkey x) where linetime within (starttime;endtime)} each (where differ tbl`date) cut tbl}

在这两个函数中,我首先从输入中删除主键属性 table。

此外,检查 nbbo 的列类型和您的输入 table。那可能会给你类型错误。这个查询对我来说工作正常。