在量化交易和金融分析领域,缠论作为一种独特的技术分析方法,近年来受到越来越多投资者的关注。CZSC库作为缠论分析的Python实现工具,其0.6.8版本提供了强大的分析功能,但许多用户在实际应用中面临一个共同挑战:如何将自己获取的Tushare、AkShare等数据源的数据,有效转换为CZSC可识别的格式进行缠论分析。本文将深入解决这一痛点,提供一套完整的解决方案。
CZSC库的核心分析类CZSC要求输入数据必须符合特定的RawBar格式。在开始数据转换前,我们需要充分理解这种数据结构的设计理念和技术细节。
RawBar本质上是一个命名元组(namedtuple),包含以下关键字段:
python复制from collections import namedtuple
RawBar = namedtuple('RawBar', [
'symbol', # 标的代码,如 '000001.SZ'
'dt', # K线结束时间,datetime对象
'open', # 开盘价
'close', # 收盘价
'high', # 最高价
'low', # 最低价
'vol' # 成交量
])
这种设计有几点值得注意的技术考量:
提示:虽然RawBar设计简洁,但实际转换时需要特别注意dt字段必须是Python的datetime对象,而非字符串或其他时间格式。
不同数据源返回的K线数据结构差异显著,我们需要针对性地设计转换方案。以下是三种常见数据源的典型数据结构和转换要点:
Tushare Pro返回的日线数据通常为Pandas DataFrame,结构如下:
| 字段名 | 类型 | 示例值 | 说明 |
|---|---|---|---|
| ts_code | str | '000001.SZ' | 股票代码 |
| trade_date | str | '20230104' | 交易日期(YYYYMMDD) |
| open | float | 15.2 | 开盘价 |
| high | float | 15.8 | 最高价 |
| low | float | 15.1 | 最低价 |
| close | float | 15.5 | 收盘价 |
| vol | float | 123456.78 | 成交量(手) |
转换时需要特别注意:
AkShare返回的数据结构更为多样,常见的是字典列表形式,例如:
python复制[
{
'date': '2023-01-04',
'open': 15.2,
'high': 15.8,
'low': 15.1,
'close': 15.5,
'volume': 12345678 # 通常为股数
},
# 更多K线数据...
]
AkShare数据特点:
Baostock返回的数据也是DataFrame,但字段命名有所不同:
| 字段名 | 类型 | 示例值 |
|---|---|---|
| code | str | 'sz.000001' |
| date | str | '2023-01-04' |
| open | float | 15.2 |
| high | float | 15.8 |
| low | float | 15.1 |
| close | float | 15.5 |
| volume | float | 12345678 |
| amount | float | 190876543.21 |
Baostock的特殊之处:
基于对不同数据源的分析,我们可以设计一个更健壮、可配置的通用转换函数。以下是完整的实现方案:
python复制from datetime import datetime
from typing import List, Union, Dict
import pandas as pd
from czsc.analyze import RawBar
def format_kline(
data: Union[pd.DataFrame, List[Dict]],
symbol: str = None,
dt_format: str = '%Y%m%d',
vol_unit: str = 'shares',
adjust: bool = False
) -> List[RawBar]:
"""
通用K线数据转换函数
参数:
data: 原始K线数据,可以是DataFrame或字典列表
symbol: 标的代码,当原始数据中不包含时需要指定
dt_format: 日期时间格式字符串
vol_unit: 成交量单位,'shares'表示股,'lots'表示手
adjust: 是否复权处理
返回:
转换后的RawBar列表
"""
bars = []
# 统一转换为记录(字典)列表形式
if isinstance(data, pd.DataFrame):
records = data.to_dict('records')
else:
records = data
for record in records:
# 处理标的代码
if symbol:
bar_symbol = symbol
else:
bar_symbol = record.get('ts_code', record.get('code', ''))
# 处理Baostock的特殊代码格式
if '.' in bar_symbol:
market, code = bar_symbol.split('.')
bar_symbol = f"{code}.{market.upper()}"
# 处理时间字段
dt_str = str(record.get('trade_date', record.get('date', '')))
try:
dt = datetime.strptime(dt_str, dt_format)
except ValueError:
# 尝试其他常见日期格式
dt = datetime.strptime(dt_str, '%Y-%m-%d')
# 处理成交量单位转换
volume = record.get('vol', record.get('volume', 0))
if vol_unit == 'lots' and 'volume' in record:
volume = volume * 100 # 手到股的转换
# 创建RawBar对象
bar = RawBar(
symbol=bar_symbol,
dt=dt,
open=float(record['open']),
close=float(record['close']),
high=float(record['high']),
low=float(record['low']),
vol=float(volume)
)
bars.append(bar)
return bars
这个增强版转换函数具有以下特点:
注意:实际使用时,应根据具体数据源调整参数。例如,Tushare数据通常需要设置dt_format='%Y%m%d'和vol_unit='lots'。
让我们通过一个完整案例,演示如何使用Tushare数据+通用转换函数+CZSC进行缠论分析。
首先,我们使用Tushare Pro获取股票日线数据:
python复制import tushare as ts
from datetime import datetime, timedelta
# 设置Tushare token(需提前申请)
ts.set_token('你的Tushare token')
pro = ts.pro_api()
# 获取贵州茅台(600519.SH)最近1000个交易日的日线数据
end_date = datetime.now().strftime('%Y%m%d')
start_date = (datetime.now() - timedelta(days=365*3)).strftime('%Y%m%d')
df = pro.daily(
ts_code='600519.SH',
start_date=start_date,
end_date=end_date
)
# 按交易日期升序排列
df = df.sort_values('trade_date')
应用我们之前构建的通用转换函数:
python复制from czsc.analyze import RawBar
# 转换Tushare数据为RawBar格式
bars = format_kline(
data=df,
dt_format='%Y%m%d',
vol_unit='lots' # Tushare成交量以手为单位
)
# 检查转换结果
print(f"成功转换 {len(bars)} 条K线数据")
print("第一条K线:", bars[0])
print("最后一条K线:", bars[-1])
现在我们可以将转换后的数据输入CZSC进行分析:
python复制from czsc.analyze import CZSC
# 创建CZSC分析器实例
czsc_analyzer = CZSC(bars, freq="日线")
# 获取最新的分析信号
latest_signals = czsc_analyzer.signals
# 打印关键信号
print("最新笔信号:", latest_signals.get('倒1笔', '无'))
print("最新分型信号:", latest_signals.get('倒1分型', '无'))
print("五笔形态:", latest_signals.get('倒1五笔', '无'))
CZSC库内置了基于Pyecharts的可视化功能:
python复制# 生成分析结果HTML文件
czsc_analyzer.to_echarts(file_html="czsc_analysis.html")
# 在Jupyter Notebook中直接显示
# czsc_analyzer.to_echarts().render_notebook()
当处理大量股票或多周期数据时,我们需要考虑效率和性能问题。以下是几个实用技巧:
python复制def analyze_stock_list(ts_codes):
results = []
for code in ts_codes:
try:
df = pro.daily(ts_code=code, start_date=start_date, end_date=end_date)
bars = format_kline(df.sort_values('trade_date'), dt_format='%Y%m%d')
analyzer = CZSC(bars, freq="日线")
results.append({
'code': code,
'signals': analyzer.signals,
'latest_price': bars[-1].close
})
except Exception as e:
print(f"分析{code}时出错:", str(e))
return results
# 分析上证50成分股
hs300 = pro.index_weight(index_code='000300.SH', start_date=end_date)
stock_list = hs300['con_code'].unique().tolist()
analysis_results = analyze_stock_list(stock_list[:10]) # 先测试前10只
缠论强调多级别联立分析,我们可以同时分析日线和30分钟线:
python复制from concurrent.futures import ThreadPoolExecutor
def multi_freq_analysis(ts_code):
# 日线分析
daily_df = pro.daily(ts_code=ts_code, start_date=start_date, end_date=end_date)
daily_bars = format_kline(daily_df.sort_values('trade_date'), dt_format='%Y%m%d')
daily_ana = CZSC(daily_bars, freq="日线")
# 30分钟线分析(使用Tushare的分钟接口)
min30_df = ts.pro_bar(ts_code=ts_code, freq='30min', start_date=start_date, end_date=end_date)
min30_bars = format_kline(min30_df.sort_values('trade_date'), dt_format='%Y%m%d%H%M')
min30_ana = CZSC(min30_bars, freq="30分钟")
return {
'code': ts_code,
'daily': daily_ana.signals,
'min30': min30_ana.signals
}
# 使用线程池加速IO密集型操作
with ThreadPoolExecutor(max_workers=5) as executor:
results = list(executor.map(multi_freq_analysis, stock_list[:5]))
为避免重复获取数据,可以实现简单的缓存机制:
python复制import pickle
import os
from hashlib import md5
CACHE_DIR = 'czsc_cache'
os.makedirs(CACHE_DIR, exist_ok=True)
def get_cached_data(ts_code, freq='daily', refresh=False):
"""带缓存的数据获取函数"""
cache_key = md5(f"{ts_code}_{freq}".encode()).hexdigest()
cache_file = os.path.join(CACHE_DIR, f"{cache_key}.pkl")
if not refresh and os.path.exists(cache_file):
with open(cache_file, 'rb') as f:
return pickle.load(f)
if freq == 'daily':
df = pro.daily(ts_code=ts_code, start_date=start_date, end_date=end_date)
else:
df = ts.pro_bar(ts_code=ts_code, freq=freq, start_date=start_date, end_date=end_date)
df = df.sort_values('trade_date')
with open(cache_file, 'wb') as f:
pickle.dump(df, f)
return df
这套本地化分析方案不仅适用于Tushare,同样可以应用于AkShare、Baostock等其他数据源。关键在于理解RawBar的数据结构要求,并据此设计适当的转换逻辑。通过构建通用的format_kline函数,我们可以实现不同数据源的无缝对接,充分发挥CZSC强大的缠论分析能力。