用Python和Pandas反算Bollinger带

2024-10-06 12:32:20 发布

您现在位置:Python中文网/ 问答频道 /正文

我正在计算pandas数据帧中滚动平均值的标准偏差(Bollinger波段,这里的示例非常简化):

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)

结果如下:

^{pr2}$

现在我想从另一个方向计算,列'A'中的最后一个值必须正好达到滚动平均值的第三个标准差。 换句话说,我要计算:下一行nr.15中的哪个值需要A,它将与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

Tags: middlesearchvaluemeannextlowlaststd
1条回答
网友
1楼 · 发布于 2024-10-06 12:32:20

这里有一个用快速算法计算下一个值的方法: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}')

输出:

^{pr2}$

您可以将牛顿优化后的结果进行比较,如下所示:

""" 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个项目

相关问题 更多 >