有效计算熊猫的控制点

问题描述 投票:0回答:3

我的算法在每天的时间范围内实施此功能时,运行时间从35秒提高到15分钟。该算法批量获取每日历史记录,并遍历数据帧的子集(从t0到tX,其中tX是迭代的当前行)。它这样做是为了模拟算法实时操作期间会发生的情况。我知道有几种方法可以通过在帧计算之间利用内存来改善它,但是我想知道是否还有更多的熊猫式实现会立即受益。

假设self.Step类似于0.00001self.Precision5;它们用于将Ohlc条信息分类为离散步骤,以便找到poc。 _frame是整个数据帧的行的子集,并且_low / _high分别对应于此。下面的代码块在整个_frame上执行,每当算法添加新行时(在按每日数据计算年度时间表时),该行可能会向上〜250行。我认为正是这种原因导致了主要的增长放缓。数据帧具有诸如highlowopenclosevolume的列。我正在计算时间价格机会和控制量点。

# Set the complete index of prices +/- 1 step due to weird floating point precision issues
volume_prices = pd.Series(0, index=np.around(np.arange(_low - self.Step, _high + self.Step, self.Step), decimals=self.Precision))
time_prices = volume_prices.copy()
for index, state in _frame.iterrows():
    _prices = np.around(np.arange(state.low, state.high, self.Step), decimals=self.Precision)
    # Evenly distribute the bar's volume over its range
    volume_prices[_prices] += state.volume / _prices.size
    # Increment time at price
    time_prices[_prices] += 1
# Pandas only returns the 1st row of the max value,
# so we need to reverse the series to find the other side
# and then find the average price between those two extremes
volume_poc = (volume_prices.idxmax() + volume_prices.iloc[::-1].idxmax()) / 2)
time_poc = (time_prices.idxmax() + time_prices.iloc[::-1].idxmax()) / 2)
python pandas finance quantitative-finance algorithmic-trading
3个回答
0
投票

您可以将此功能用作基础并进行调整:

def f(x):                             #function to find the POC price and volume
    a = x['tradePrice'].value_counts().index[0]
    b = x.loc[x['tradePrice'] == a, 'tradeVolume'].sum()
    return pd.Series([a,b],['POC_Price','POC_Volume'])

0
投票

这是我的工作。我仍然不确定您的代码产生的答案是否正确,我认为您的行volume_prices[_prices] += state.Volume / _prices.size并未应用到volume_prices中的每条记录,但这里是基准测试。大约提高了9倍。

def vpOriginal():
    Step = 0.00001
    Precision = 5
    _frame = getData()
    _low = 85.0
    _high = 116.4
    # Set the complete index of prices +/- 1 step due to weird floating point precision issues
    volume_prices = pd.Series(0, index=np.around(np.arange(_low - Step, _high + Step, Step), decimals=Precision))
    time_prices = volume_prices.copy()
    time_prices2 = volume_prices.copy()
    for index, state in _frame.iterrows():
        _prices = np.around(np.arange(state.Low, state.High, Step), decimals=Precision)

        # Evenly distribute the bar's volume over its range
        volume_prices[_prices] += state.Volume / _prices.size
        # Increment time at price
        time_prices[_prices] += 1
    time_prices2 += 1
    # Pandas only returns the 1st row of the max value,
    # so we need to reverse the series to find the other side
    # and then find the average price between those two extremes
#    print(volume_prices.head(10))
    volume_poc = (volume_prices.idxmax() + volume_prices.iloc[::-1].idxmax() / 2)
    time_poc = (time_prices.idxmax() + time_prices.iloc[::-1].idxmax() / 2)
    return volume_poc, time_poc

def vpNoDF():
    Step = 0.00001
    Precision = 5
    _frame = getData()
    _low = 85.0
    _high = 116.4
    # Set the complete index of prices +/- 1 step due to weird floating point precision issues
    volume_prices = pd.Series(0, index=np.around(np.arange(_low - Step, _high + Step, Step), decimals=Precision))
    time_prices = volume_prices.copy()
    for index, state in _frame.iterrows():
        _prices = np.around((state.High - state.Low) / Step , 0)

        # Evenly distribute the bar's volume over its range
        volume_prices.loc[state.Low:state.High] += state.Volume / _prices
        # Increment time at price
        time_prices.loc[state.Low:state.High] += 1

    # Pandas only returns the 1st row of the max value,
    # so we need to reverse the series to find the other side
    # and then find the average price between those two extremes
    volume_poc = (volume_prices.idxmax() + volume_prices.iloc[::-1].idxmax() / 2)
    time_poc = (time_prices.idxmax() + time_prices.iloc[::-1].idxmax() / 2)
    return volume_poc, time_poc

getData()
Out[8]: 
         Date    Open    High     Low   Close    Volume  Adj Close
0  2008-10-14  116.26  116.40  103.14  104.08  70749800     104.08
1  2008-10-13  104.55  110.53  101.02  110.26  54967000     110.26
2  2008-10-10   85.70  100.00   85.00   96.80  79260700      96.80
3  2008-10-09   93.35   95.80   86.60   88.74  57763700      88.74
4  2008-10-08   85.91   96.33   85.68   89.79  78847900      89.79
5  2008-10-07  100.48  101.50   88.95   89.16  67099000      89.16
6  2008-10-06   91.96   98.78   87.54   98.14  75264900      98.14
7  2008-10-03  104.00  106.50   94.65   97.07  81942800      97.07
8  2008-10-02  108.01  108.79  100.00  100.10  57477300     100.10
9  2008-10-01  111.92  112.36  107.39  109.12  46303000     109.12

vpOriginal()
Out[9]: (142.55000000000001, 142.55000000000001)

vpNoDF()
Out[10]: (142.55000000000001, 142.55000000000001)

%timeit vpOriginal()
2.79 s ± 24.3 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

%timeit vpNoDF()
300 ms ± 8.04 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

0
投票

无论如何,我每天都将时间降为2分钟,而不是15分钟。在较短的时间范围内(2年内,每小时10分钟,对于股票而言,精度为2)仍然很慢。使用DataFrames而不是Series的速度要慢一些。我希望得到更多,但除了以下解决方案外,我不知道该怎么办:

# Upon class instantiation, I've created attributes for each timeframe
# related to `volume_at_price` and `time_at_price`. They serve as memory
# in between frame calculations
def _prices_at(self, frame, bars=0):
    # Include 1 step above high as np.arange does not
    # include the upper limit by default
    state = frame.iloc[-min(bars + 1, frame.index.size)]
    bins = np.around(np.arange(state.low, state.high + self.Step, self.Step), decimals=self.Precision)
    return pd.Series(state.volume / bins.size, index=bins)


# SetFeature/Feature implement timeframed attributes (i.e., 'volume_at_price_D')
_v = 'volume_at_price'
_t = 'time_at_price'

# Add to x_at_price histogram
_p = self._prices_at(frame)
self.SetFeature(_v, self.Feature(_v).add(_p, fill_value=0))
self.SetFeature(_t, self.Feature(_t).add(_p * 0 + 1, fill_value=0))

# Remove old data from histogram
_p = self._prices_at(frame, self.Bars)
v = self.SetFeature(_v, self.Feature(_v).subtract(_p, fill_value=0))
t = self.SetFeature(_t, self.Feature(_t).subtract(_p * 0 + 1, fill_value=0))

self.SetFeature('volume_poc', (v.idxmax() + v.iloc[::-1].idxmax()) / 2)
self.SetFeature('time_poc', (t.idxmax() + t.iloc[::-1].idxmax()) / 2)
© www.soinside.com 2019 - 2024. All rights reserved.