我正在处理大熊猫的日内时间和报价数据,并努力找到一个很好的方法来计算加权的中间价格。我目前将数据表示为四个数据帧(bid_price,bid_quantity,ask_price,ask_quantity),每个数据帧的列是单独的工具,索引是时间戳。 (因此,单个出价可以引用为:
bid_price['AAPL'][datetime(2013,1,1,9,30,0,0)]
我希望应用的中点公式取决于工具的买/卖差价。如果当前价差比最小价格增量宽,则中点将是当时买入价和卖出价的简单平均值。如果差价等于最小值,则根据买入和卖出数量对中点进行加权。
以下是当前代码:
def get_midprice(bid_price, bid_quantity, ask_price, ask_quantity, tick_increment=0.01):
if (ask_price - bid_price) > tick_increment:
return (ask_price + bid_price) / 2
else:
return ((bid_price * ask_quantity) + (ask_price * bid_quantity)) / (bid_quantity + ask_quantity)
这适用于单个数据点,并且在以前版本的pandas上,它在传递4个DataFrame时也有效。现在,4个数据帧引发了异常:
raise ValueError("Cannot call bool() on DataFrame.")
ValueError: Cannot call bool() on DataFrame.
我认为这是由于这一变化:https://github.com/pydata/pandas/pull/1073
问题显然可以通过循环解决,但在大型数据集上,这非常慢。还有更好的方法吗?
答案 0 :(得分:1)
正如我在评论中尝试传达的那样,你无法按照你尝试的方式对if
分支进行向量化,因此虽然代码在过去没有引发异常,但几乎可以肯定没有做你想要的。这就是array
s(现在DataFrame
s)在调用bool()
时出错的原因,以帮助避免此错误。
这方面的一个方法是一个apply-elementwise函数,它通过在(有效)压缩相应元素上应用函数来构建新的DataFrame
。可能有一个,虽然我还没有用过它。 (我支持添加一个。有时它很方便,在我们自己开发的n维C#库中,我有一个apply-to-matched-elements函数。)
通常当我需要做这样的前熊猫之类的事情时,我只是计算了两个分支然后合并了结果(利用了False~0和True~1这一事实):
>>> a = np.arange(10)
>>> a > 3
array([False, False, False, False, True, True, True, True, True, True], dtype=bool)
>>> w = a > 3
>>> (a**2) * w + (1000) * (1-w)
array([1000, 1000, 1000, 1000, 16, 25, 36, 49, 64, 81])
但在numpy
和pandas
中我们也可以使用where
,因此您的代码的一个版本将是:
def get_midprice(bp, bq, ap, aq, ti):
above = (ap + bp)/2
not_above = ((bp*aq) + (ap*bq))/(bq+aq)
use_above = (ap - bp) > ti
combined = not_above.where(use_above, above)
return combined
这种方法的缺点是你必须计算两个分支,并且它使用更多的内存。在实践中,它很少引起我的问题,但YMMV。请注意,使用乘法(即使速度稍慢)而不是where
的一个小优点是它在传递标量时也能正常工作。
最后,您还可以考虑更改格式以将信息保持在一起,可能使用分层多索引,但我没有太多经验。