A股量化策略回测实战:从行情数据到绩效评估(第 15 篇):新高新低策略
前言
创 N 日新高 = 当前价格站在一段时间最高点,是趋势最强的表达;创 N 日新低 = 站在最低点,是恐慌极点,常伴随反弹。本篇用 himk 真实的阶段最高/最低数据,做新高买入(趋势跟随)与新低反弹(反转)两类策略。
一、接口原始字段梳理
1)himk/jdzgzd 阶段最高最低
字段来自官网说明(零编造),共 19 个,关键是各周期最高/最低:
| 字段 | 含义 |
|---|---|
t |
交易日 |
dm, mc |
代码、名称 |
g5, g10, g20, g60 |
5/10/20/60 日最高价 |
d5, d10, d20, d60 |
5/10/20/60 日最低价 |
zd5, zd10, zd20, zd60 |
对应区间最大涨跌幅 |
iscq5, iscq10, iscq20, iscq60 |
是否次新(区间) |
路径:{BASE}/himk/jdzgzd/{licence}(返回全市场阶段高低,按 t 取最新)。本篇用 g20/d20(20 日)做信号,另需个股当日收盘 c(来自 hsstock/history)确认是否触达极值。
二、自研衍生统计指标
- 创新高 = 个股当日收盘
c_t >= g20(站在 20 日最高)→ 趋势买入。 - 创新低 =
c_t <= d20(站在 20 日最低)→ 超跌反弹买入。 - 次新过滤
iscq20==1的标的波动异常,策略可选剔除。 - 用
gN/dN(接口预制极值)+ 当日c判定,避免自己算区间最高最低(省事且口径一致)。
三、数据表设计
sql
CREATE TABLE IF NOT EXISTS hl_event (
t TEXT NOT NULL,
dm TEXT NOT NULL,
g20 REAL, d20 REAL,
iscq INTEGER,
sig TEXT, -- NEWHIGH/NEWLOW/HOLD
PRIMARY KEY (t, dm)
);
四、完整代码
4.1 新高/新低信号
python
import sqlite3, json, time
BASE = "https://api.biyingapi.com"
LICENCE = "YOUR_LICENCE_HERE"
DB_PATH = "backtest.db"
def biying_api_get_retry(url, timeout=15, max_retry=3):
import urllib.request
last = None
for i in range(max_retry):
try:
req = urllib.request.Request(url, headers={'User-Agent': 'Mozilla/5.0'})
with urllib.request.urlopen(req, timeout=timeout) as r:
return json.loads(r.read().decode('utf-8', 'ignore'))
except Exception as e:
last = e
if i < max_retry - 1:
time.sleep(1 + i)
raise last
def fetch_hl_pool():
url = f"{BASE}/himk/jdzgzd/{LICENCE}"
data = biying_api_get_retry(url)
return data if isinstance(data, list) else data.get('data', [])
def fetch_daily_close(stock, date, adj='f'):
url = (f"{BASE}/hsstock/history/{stock}/d/{adj}/{LICENCE}"
f"?st={date}&et={date}<=5")
data = biying_api_get_retry(url)
bars = data if isinstance(data, list) else data.get('data', [])
return float(bars[-1]['c']) if bars else None
def hl_signal(pool, closes, n=20, skip_subnew=True):
"""新高/新低信号(纯计算)。closes: {dm: 当日收盘}。"""
out = []
gk, dk = f'g{n}', f'd{n}'
for r in pool:
dm = r['dm']
g = r.get(gk); d = r.get(dk)
if g is None or d is None:
out.append((dm, 'HOLD')); continue
if skip_subnew and int(r.get(f'iscq{n}', 0) or 0) == 1:
out.append((dm, 'HOLD')); continue
c = closes.get(dm)
if c is None:
out.append((dm, 'HOLD')); continue
if c >= float(g):
out.append((dm, 'NEWHIGH'))
elif c <= float(d):
out.append((dm, 'NEWLOW'))
else:
out.append((dm, 'HOLD'))
return out
def demo_hl():
pool = [{'dm': '600000.SH', 'mc': '浦发', 'g20': 12.0, 'd20': 10.0, 'iscq20': 0}]
closes = {'600000.SH': 12.1} # 收盘>=g20 → 创新高
print(hl_signal(pool, closes, n=20))
if __name__ == '__main__':
demo_hl()
五、关键业务说明
- 新高 ≠ 马上追:创新高后可能继续趋势(动量)也可能见顶回落;纯新高策略本质是"追强",需配合止损(第 27 篇)。
- 新低反弹胜率看环境:熊市里"新低之后还有新低",单纯抄底危险;常需"新低 + 放量企稳"等确认。
- 周期选择 :
g20/d20偏短、g60/d60偏长;长周期新高更"真",但信号更少。 - 次新股干扰 :
iscq次新标的上市不久,高低区间失真,建议剔除(接口直接给标记,省事)。
六、拓展练习
- 分别回测"新高买入持有 N 日"与"新低反弹持有 N 日"的胜率,对比哪种更稳。
- 把新高信号与第 6 篇多头排列叠加,做"强势中的强势"。
- 用
zd20(区间最大涨跌幅)过滤:仅参与区间涨幅适中的标的,避开已暴涨。 - 把新高/新低标记接第 25 篇组合,做月度调仓的趋势组合。
下篇预告
系列第 16 篇:价值、低 PE、PB 策略 ------ 量价之外进入基本面 。下一篇用 himk 真实的市盈率/市净率排行,做低估值(低 PE/PB)选股,并讨论价值因子的有效性与陷阱。
免责申明 :本篇全部代码与回测结果仅作为量化编程与策略研究的学习演示,所有回测均为方法演示,不构成任何投资建议。市场有风险,投资需谨慎。