布林带(Bollinger Bands)也称为布林通道、保力加通道,是由约翰·布林格(John Bollinger)发明的技术分析指标。布林通道通常被用来确认资产价格波动范围。
布林通道是由三条平滑的曲线组成的趋势线图表,中线为均线,上/下线为中线±2个标准差。
在上一个章节没有自己造轮子,直接使用 Pandas 函数计算 MACD,非常方便的实现了计算和绘图。
本次使用更快捷的方式,直接上飞机:使用 AI 来写代码。
我在上篇文章《利用AI快速跨过新手区:用DevChat编写Python程序》 介绍了如何使用 DevChat 编写程序。
这次直接借助 DevChat 来编写布林带并绘图。
AI 编程
因为数据源来源不一致,对程序进行修改,直接套用之前的代码。
import pandas as pd
import matplotlib
import matplotlib.pyplot as plt
import requests
import json
from requests.auth import HTTPBasicAuth
import datetime
import numpy as np
import fun
## def global variables
global dbname
global stbname
global username
global password
global tdurl
global logfile
dbname = 'trade_data_a'
stbname = 'tdata'
username = 'root'
password = 'taosdata'
## 如果是本地数据库将地址修改为localhost
tdurl = 'http://10.7.7.14:6041/rest/sql/trade_data_a?tz=Asia/Shanghai'
logfile = 'error.log'
##SQL
st = '2022-06-01'
et = '2022-10-01'
sql = 'select tdate,close from trade_data_c.tdata where fcode="000001" and tdate>="'+st+'" and tdate<="'+et+'"'
## Get data to DataFrame
def request_get_d(resInfo):
load_data = json.loads(resInfo)
data = load_data.get("data")
df = pd.DataFrame(data)
df.rename(columns={0:'tdate',1:'close'},inplace=True)
return df
if __name__ == '__main__':
# 指定默认字体
matplotlib.rcParams['font.sans-serif'] = ['SimHei']
matplotlib.rcParams['font.family']='sans-serif'
# 解决保存图像是负号'-'显示为方块的问题
matplotlib.rcParams['axes.unicode_minus'] = False
rt = fun.request_post(tdurl,sql,username,password)
scode = fun.check_return(rt)
if scode != 'error':
df = request_get_d(rt)
# 计算20日移动平均线、标准差、布林上线和布林下线
df['20日MA'] = df['close'].rolling(window=20).mean()
df['20日STD'] = df['close'].rolling(window=20).std()
df['布林上线'] = df['20日MA'] + (df['20日STD'] * 2)
df['布林下线'] = df['20日MA'] - (df['20日STD'] * 2)
# 绘制布林带
df[['close','20日MA','布林上线','布林下线']].plot(figsize=(12,6))
plt.title('平安银行布林带')
plt.ylabel('价格 (人民币)')
plt.show()
运行脚本,图形可以正常绘制,但是中文显示有问题。不过不急,直接问AI。
修改后图形就显示正常了。
程序优化
利用 DevChat 对程序进行进一步优化:
import pandas as pd
import matplotlib.pyplot as plt
import requests
import json
from matplotlib import font_manager
# Global variables
DB_NAME = 'trade_data_a'
STB_NAME = 'tdata'
USERNAME = 'root'
PASSWORD = 'taosdata'
TD_URL = 'http://10.7.7.14:6041/rest/sql/trade_data_a?tz=Asia/Shanghai'
LOG_FILE = 'error.log'
# Constants
START_DATE = '2022-06-01'
END_DATE = '2022-10-01'
SQL = f'select tdate,close from trade_data_c.tdata where fcode="000001" and tdate>="{START_DATE}" and tdate<="{END_DATE}"'
# Specify default font
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['font.family'] = 'sans-serif'
# Resolve issue with negative numbers being displayed as a square
plt.rcParams['axes.unicode_minus'] = False
def request_get_d(resInfo):
load_data = json.loads(resInfo)
data = load_data.get("data")
df = pd.DataFrame(data)
df.rename(columns={0: 'tdate', 1: 'close'}, inplace=True)
return df
if __name__ == '__main__':
rt = fun.request_post(TD_URL, SQL, USERNAME, PASSWORD)
scode = fun.check_return(rt)
if scode != 'error':
df = request_get_d(rt)
# Calculate 20-Day Moving Average, Standard Deviation, Upper Band and Lower Band
df['20 Day MA'] = df['close'].rolling(window=20).mean()
df['20 Day STD'] = df['close'].rolling(window=20).std()
df['Upper Band'] = df['20 Day MA'] + (df['20 Day STD'] * 2)
df['Lower Band'] = df['20 Day MA'] - (df['20 Day STD'] * 2)
# Draw Bollinger Bands
df[['close', '20 Day MA', 'Upper Band', 'Lower Band']].plot(figsize=(12, 6))
plt.title('Ping An Bank Bollinger Bands')
plt.ylabel('Price')
plt.show()
别的不说,起码看上去挺漂亮的。不过有两个小问题:
import fun
被删除了,这是我的一个存储函数的文件,不引用这个,很多自定义函数会报错。- 中文名称变英文了。
进阶
直接让 DevChat 编写完整的程序。
import taos
import pandas as pd
import numpy as np
from matplotlib import pyplot as plt
# 连接到 TDengine 数据库
conn = taos.connect(host='10.7.7.14', user='root', password='taosdata', database='trade_data_c')
# 查询一段时间内的收盘价
query = "select tdate,close from trade_data_c.tdata where fcode='000001' and tdate>= '2022-03-01' AND tdate <= '2023-02-28'"
result = conn.query(query)
df = pd.DataFrame(result.fetch_all(), columns=['Timestamp', 'Close'])
df['Timestamp'] = pd.to_datetime(df['Timestamp'])
df.set_index('Timestamp', inplace=True)
# 计算20日均线和标准差
df['20 Day MA'] = df['Close'].rolling(window=20).mean()
df['20 Day STD'] = df['Close'].rolling(window=20).std()
# 计算布林带上线和下线
df['Upper Band'] = df['20 Day MA'] + (df['20 Day STD'] * 2)
df['Lower Band'] = df['20 Day MA'] - (df['20 Day STD'] * 2)
# 绘制布林带图形
plt.figure(figsize=(12, 6))
plt.plot(df.index, df['Close'], label='Close')
plt.plot(df.index, df['Upper Band'], label='Upper Band')
plt.plot(df.index, df['Lower Band'], label='Lower Band')
plt.title('Bollinger Bands')
plt.xlabel('Timestamp')
plt.ylabel('Price')
plt.legend()
plt.show()
# 提示买卖信号
last_close = df['Close'].iloc[-1]
last_upper_band = df['Upper Band'].iloc[-1]
last_lower_band = df['Lower Band'].iloc[-1]
if last_close > last_upper_band:
print('做空')
elif last_close < last_lower_band:
print('做多')
else:
print('继续观察')
有一种要失业的预感!!
题外话
布林带或者叫布林通道,顾名思义,绘制了一条以均线为中心,4倍标准差宽度的通道。
和 MACD 一样,布林带依然是对价格趋势的描述,只是相较于 MACD 描述趋势的变化程度,布林带更关注于价格的异常波动。
要搞懂布林带,就需要从定义入手,除了之前提到的均线,另一个重要的概念就是标准差。
标准差是反映一组数据离散程度最常用的一种量化形式,是表示精确度的重要指标。标准差的计算步骤如下:
- 求平均:计算数据集中数值的平均值。
- 计算每个数值与平均值的差:从每个数值中减去平均值,然后求差的平方。
- 求结果的平均:将所有差的平方相加,然后除以数据集中的数值个数,再取平方根。
由此看出,布林带绘制了一条价格变化的通道,在绝大多数情况下,价格会处于通道内,并围绕中线上下波动。
对于单边趋势(如上涨),价格如果突破布林带,说明开始了加速行情。
对于震荡趋势,价格如果突破了布林带,说明要开始回调或突破。
世界上并不存在圣杯和银弹,像盲人摸象一样,任何指标都只能反应市场的一部分,而且计算的过程越复杂,离真是可能越远。