【问题标题】:Back-calculating Bollinger Bands with python and pandas用 python 和 pandas 反算布林带
【发布时间】:2019-03-17 00:45:38
【问题描述】:

我正在计算熊猫数据框中滚动平均值(布林带,此处的示例非常简化)的标准偏差,如下所示:

import pandas as pd
import numpy as np

no_of_std = 3
window = 20

df = pd.DataFrame({'A': [34, 34, 34, 33, 32, 34, 35.0, 21, 22, 25, 23, 21, 39, 26, 31, 34, 38, 26, 21, 39, 31]})

rolling_mean = df['A'].rolling(window).mean()
rolling_std = df['A'].rolling(window).std(ddof=0)

df['M'] = rolling_mean
df['BBL'] = rolling_mean - (rolling_std * no_of_std)
df['BBH'] = rolling_mean + (rolling_std * no_of_std)

print (df)

结果如下:

       A      M        BBL        BBH
0   34.0    NaN        NaN        NaN
1   34.0    NaN        NaN        NaN
2   34.0    NaN        NaN        NaN
3   33.0    NaN        NaN        NaN
4   32.0    NaN        NaN        NaN
5   34.0    NaN        NaN        NaN
6   35.0    NaN        NaN        NaN
7   21.0    NaN        NaN        NaN
8   22.0    NaN        NaN        NaN
9   25.0    NaN        NaN        NaN
10  23.0    NaN        NaN        NaN
11  21.0    NaN        NaN        NaN
12  39.0    NaN        NaN        NaN
13  26.0    NaN        NaN        NaN
14  31.0    NaN        NaN        NaN
15  34.0    NaN        NaN        NaN
16  38.0    NaN        NaN        NaN
17  26.0    NaN        NaN        NaN
18  21.0    NaN        NaN        NaN
19  39.0  30.10  11.633544  48.566456
20  31.0  29.95  11.665375  48.234625

现在我想在另一个方向计算“A”列中的最后一个值需要准确达到滚动平均值的第三个标准偏差。 这意味着换句话说,我想计算:A 在下一行 nr.15 中需要哪个值,它将与 BBH 或 BBL 中的值完全相同。 我可以通过递归近似来做到这一点,但这需要很多性能,我认为必须有更好的方法。这是我认为它会变慢并且必须有更好更快的方法的解决方案示例:

import pandas as pd


odf = pd.DataFrame({'A': [34, 34, 34, 33, 32, 34, 35.0, 21, 22, 25, 23, 21, 39, 26, 31, 34, 38, 26, 21, 39, 31]})

def get_last_bbh_bbl(idf):
    xdf = idf.copy()
    no_of_std = 3
    window = 20
    rolling_mean = xdf['A'].rolling(window).mean()
    rolling_std = xdf['A'].rolling(window).std()
    xdf['M'] = rolling_mean
    xdf['BBL'] = rolling_mean - (rolling_std * no_of_std)
    xdf['BBH'] = rolling_mean + (rolling_std * no_of_std)
    bbh = xdf.loc[len(xdf) - 1, 'BBH']
    bbl = xdf.loc[len(xdf) - 1, 'BBL']
    return bbh, bbl

def search_matching_value(idf, low, high, search_for):
    xdf = idf.copy()
    if abs(high-low) < 0.000001:
        return high

    middle = low + ((high-low)/2)
    xdf = xdf.append({'A' : middle}, ignore_index=True)
    bbh, bbl = get_last_bbh_bbl(xdf)
    if search_for == 'bbh':
        if bbh < middle:
            result=search_matching_value(idf, low, middle, search_for)
        elif bbh > middle:
            result=search_matching_value(idf, middle, high, search_for)
        else:
            return middle
    elif search_for == 'bbl':
        if bbl > middle:
            result=search_matching_value(idf, middle, high, search_for)
        elif bbl < middle:
            result=search_matching_value(idf, low, middle, search_for)
        else:
            return middle
    return result

actual_bbh, actual_bbl = get_last_bbh_bbl(odf)
last_value = odf.loc[len(odf) - 1, 'A']
print('last_value: {}, actual bbh: {}, actual bbl: {}'.format(last_value, actual_bbh, actual_bbl))
low = last_value
high = actual_bbh * 10
next_value_that_hits_bbh = search_matching_value(odf, low, high, 'bbh')
print ('next_value_that_hits_bbh: {}'.format(next_value_that_hits_bbh))
low=0
high=last_value
next_value_that_hits_bbl = search_matching_value(odf, low, high, 'bbl')
print ('next_value_that_hits_bbl: {}'.format(next_value_that_hits_bbl))

结果如下所示:

 last_value: 31.0, actual bbh: 48.709629106422284, actual bbl: 11.190370893577711
 next_value_that_hits_bbh: 57.298733206475276
 next_value_that_hits_bbl: 2.174952656030655

【问题讨论】:

  • 你会发现 A 中的下一个值与 M 、 BBL 和 BBH 中的最后一个值相同?
  • 不,我想知道与 BBl 或 BBH 相同的 A 的下一个值。 I A 越高,我得到的 BBH 越高,依此类推。目前我用递归来做到这一点。
  • 可以递归,但是使用二分法很快?
  • 我更改了示例,窗口小了十个单位,并添加了递归示例
  • 我已经修复了我的错误,新的解决方案似乎还可以......我的结果和你的一样!!

标签: python pandas


【解决方案1】:

这里有一个用快速算法计算下一个值的解决方案:newton opt 和 newton classic 比二分法更快,而且这个解决方案不使用数据框来重新计算不同的值,我直接使用同名库中的统计函数

scipy.optimize.newton的一些信息

from scipy import misc
import pandas as pd
import statistics
from scipy.optimize import newton
#scipy.optimize if you want to test the newton optimized function

def get_last_bbh_bbl(idf):
    xdf = idf.copy()
    rolling_mean = xdf['A'].rolling(window).mean()
    rolling_std = xdf['A'].rolling(window).std()
    xdf['M'] = rolling_mean
    xdf['BBL'] = rolling_mean - (rolling_std * no_of_std)
    xdf['BBH'] = rolling_mean + (rolling_std * no_of_std)
    bbh = xdf.loc[len(xdf) - 1, 'BBH']
    bbl = xdf.loc[len(xdf) - 1, 'BBL']
    lastvalue = xdf.loc[len(xdf) - 1, 'A']
    return lastvalue, bbh, bbl

#classic newton
def NewtonsMethod(f, x, tolerance=0.00000001):
    while True:
        x1 = x - f(x) / misc.derivative(f, x)
        t = abs(x1 - x)
        if t < tolerance:
            break
        x = x1
    return x

#to calculate the result of function bbl(x) - x (we want 0!)
def low(x):
    l = lastlistofvalue[:-1]
    l.append(x)
    avg = statistics.mean(l)
    std = statistics.stdev(l, avg)
    return avg - std * no_of_std - x

#to calculate the result of function bbh(x) - x (we want 0!)
def high(x):
    l = lastlistofvalue[:-1]
    l.append(x)
    avg = statistics.mean(l)
    std = statistics.stdev(l, avg)
    return avg + std * no_of_std - x

odf = pd.DataFrame({'A': [34, 34, 34, 33, 32, 34, 35.0, 21, 22, 25, 23, 21, 39, 26, 31, 34, 38, 26, 21, 39, 31]})
no_of_std = 3
window = 20
lastlistofvalue = odf['A'].shift(0).to_list()[::-1][:window]

"""" Newton classic method """
x = odf.loc[len(odf) - 1, 'A']
x0 = NewtonsMethod(high, x)
print(f'value to hit bbh: {x0}')
odf = pd.DataFrame({'A': [34, 34, 34, 33, 32, 34, 35.0, 21, 22, 25, 23, 21, 39, 26, 31, 34, 38, 26, 21, 39, 31, x0]})
lastvalue, new_bbh, new_bbl = get_last_bbh_bbl(odf)
print(f'value to hit bbh: {lastvalue} -> check new bbh: {new_bbh}')

x0 = NewtonsMethod(low, x)
print(f'value to hit bbl: {x0}')
odf = pd.DataFrame({'A': [34, 34, 34, 33, 32, 34, 35.0, 21, 22, 25, 23, 21, 39, 26, 31, 34, 38, 26, 21, 39, 31, x0]})
lastvalue, new_bbh, new_bbl = get_last_bbh_bbl(odf)
print(f'value to hit bbl: {lastvalue} -> check new bbl: {new_bbl}')

输出:

value to hit bbh: 57.298732375228624
value to hit bbh: 57.298732375228624 -> check new bbh: 57.29873237527272
value to hit bbl: 2.1749518354059636
value to hit bbl: 2.1749518354059636 -> check new bbl: 2.1749518353102992

你可以比较牛顿优化像:

""" Newton optimized method """
x = odf.loc[len(odf) - 1, 'A']
x0 = newton(high, x, fprime=None, args=(), tol=1.00e-08, maxiter=50, fprime2=None)
print(f'Newton opt value to hit bbh: {x0}')

x0 = newton(low, x, fprime=None, args=(), tol=1.48e-08, maxiter=50, fprime2=None)
print(f'Newton value to hit bbl: {x0}')

输出:

Newton opt value to hit bbh: 57.29873237532118
Newton value to hit bbl: 2.1749518352051225

优化牛顿,你可以玩最大迭代

并且优化比经典更快:

每个微积分的度量

0.002 秒优化

经典 0.005 秒

*备注:*

如果你使用 rolling(window).std() 你使用的是标准差,所以你必须使用

std = statistics.stdev(l, avg)你除以N-1项

如果你使用 rolling(window).std(ddof=0) 你正在使用总体偏差,所以你必须使用

std = statistics.pstdev(l, avg)你除以N项

【讨论】:

  • 我想知道 A 的哪个值与 BBL 相同,A 的哪个值与 BBH 相同。
  • 查看我的解决方案
  • 值不能正确。第 14 行中的上布林带 (BBH) 为 50.37。所以 bbh 的结果必须比 37.66 更接近这个值。如果我将 37.66 的结果添加到数据帧( df = pd.DataFrame({'A': [35.0, 21, 22, 25, 23, 21, 39, 26, 31, 34, 38, 26, 21, 39 , 31, 37.66]}) ) 我在最后一个 BBH 中得到 50.37。
  • 我更改了示例,窗口很小,只有十个单位,并添加了递归示例
  • 我已修复我的错误以测试值 action = bbh 或 value = bbl ... 而不是 bbh 或 bbl = bbh 或 bbl 的最后一个值
猜你喜欢
  • 2022-11-02
  • 2013-11-30
  • 1970-01-01
  • 2015-02-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多