Skip to content

Commit

Permalink
V0.9.49 更新一批代码 (waditu#194)
Browse files Browse the repository at this point in the history
* 09.49 start coding

* 0.9.49 update_nxb 支持多品种

* 0.9.49 remove FeatureAnalyzeBase

* 0.9.49 新增支撑压力位判断信号

* 0.9.49 新增 overlap 分析

* 0.9.49 新增信号函数

* 0.9.49 新增信号函数

* 0.9.49 新增 overlap 计算

* 0.9.49 新增 psi 计算

* 0.9.49 新增盈亏比判断相关的信号函数

* 0.9.49 优化 name hash 方法

* 0.9.49 新增加速走势的识别方法

* 0.9.49 update

* 0.9.49 fix libxml2-dev libxslt1-dev

* 0.9.49 fix libxml2-dev libxslt-dev python-dev

* 0.9.49 fix libxml2-dev libxslt-dev

* 0.9.49 lxml==4.9.2

* 0.9.49 lxml==4.9.2

* 0.9.49 新增保本单处理信号

* 0.9.49 新增事件因子的收益率特征分析

* 0.9.49 新增事件因子的收益率特征分析

* 0.9.49 确定了一批 deprecated 函数

* 0.9.49 新增K线质量检查函数

* 0.9.49 新增两个信号函数

* 0.9.49 新增 max_overlap

* 0.9.49 新增止盈止损信号函数

* 0.9.49 新增交易单元分析组件

* 0.9.49 fix nh_daily

* 0.9.49 tushare cache api example
  • Loading branch information
zengbin93 authored May 4, 2024
1 parent f048e1c commit 972f960
Show file tree
Hide file tree
Showing 37 changed files with 2,625 additions and 1,121 deletions.
9 changes: 7 additions & 2 deletions .github/workflows/pythonpackage.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ name: Python package

on:
push:
branches: [ master, V0.9.48 ]
branches: [ master, V0.9.49 ]
pull_request:
branches: [ master ]

Expand All @@ -15,17 +15,22 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: [3.7, 3.8, 3.9, '3.10', '3.11', '3.12']
python-version: [3.7, 3.8, 3.9, '3.10', '3.11']

steps:
- uses: actions/checkout@v2
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v1
with:
python-version: ${{ matrix.python-version }}
- name: Install libxml2 and libxslt
run: |
sudo apt-get update
sudo apt-get install -y libxml2-dev libxslt-dev
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install lxml==4.9.2
pip install -r requirements.txt
- name: Lint with flake8
run: |
Expand Down
24 changes: 20 additions & 4 deletions czsc/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
from czsc.objects import Freq, Operate, Direction, Signal, Factor, Event, RawBar, NewBar, Position, ZS
from czsc.strategies import CzscStrategyBase, CzscJsonStrategy
from czsc.sensors import holds_concepts_effect, CTAResearch, EventMatchSensor
from czsc.sensors.feature import FixedNumberSelector, FeatureAnalyzeBase
from czsc.sensors.feature import FixedNumberSelector
from czsc.traders import (
CzscTrader,
CzscSignals,
Expand Down Expand Up @@ -45,6 +45,8 @@
ExitsOptimize,
)
from czsc.utils import (
overlap,

format_standard_kline,

KlineChart,
Expand All @@ -69,7 +71,7 @@
cal_trade_price,
update_bbars,
update_tbars,
update_nbars,
update_nxb,
risk_free_returns,
resample_to_daily,

Expand All @@ -85,6 +87,7 @@
net_value_stats,
subtract_fee,
top_drawdowns,
psi,

home_path,
DiskCache,
Expand Down Expand Up @@ -132,6 +135,10 @@
show_optuna_study,
show_drawdowns,
show_rolling_daily_performance,
show_event_return,
show_psi,
show_strategies_symbol,
show_strategies_dailys,
)

from czsc.utils.bi_info import (
Expand Down Expand Up @@ -160,10 +167,19 @@
normalize_corr,
)

__version__ = "0.9.48"

from czsc.utils.kline_quality import (
check_high_low,
check_price_gap,
check_abnormal_volume,
check_zero_volume,
)


__version__ = "0.9.49"
__author__ = "zengbin93"
__email__ = "[email protected]"
__date__ = "20240410"
__date__ = "20240419"


def welcome():
Expand Down
122 changes: 69 additions & 53 deletions czsc/connectors/cooperation.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
# czsc.set_url_token(token='your token', url='http://zbczsc.com:9106')

cache_path = os.getenv("CZSC_CACHE_PATH", os.path.expanduser("~/.quant_data_cache"))
dc = czsc.DataClient(url='http://zbczsc.com:9106', cache_path=cache_path)
dc = czsc.DataClient(url="http://zbczsc.com:9106", cache_path=cache_path)


def format_kline(kline: pd.DataFrame, freq: Freq):
Expand All @@ -41,9 +41,18 @@ def format_kline(kline: pd.DataFrame, freq: Freq):
"""
bars = []
for i, row in kline.iterrows():
bar = RawBar(symbol=row['code'], id=i, freq=freq, dt=row['dt'],
open=row['open'], close=row['close'], high=row['high'],
low=row['low'], vol=row['vol'], amount=row['amount'])
bar = RawBar(
symbol=row["code"],
id=i,
freq=freq,
dt=row["dt"],
open=row["open"],
close=row["close"],
high=row["high"],
low=row["low"],
vol=row["vol"],
amount=row["amount"],
)
bars.append(bar)
return bars

Expand All @@ -61,26 +70,26 @@ def get_symbols(name, **kwargs):
return symbols

if name == "ETF":
df = dc.etf_basic(v=2, fields='code,name', ttl=3600 * 6)
df = dc.etf_basic(v=2, fields="code,name", ttl=3600 * 6)
dfk = dc.pro_bar(trade_date="2024-04-02", asset="e", v=2)
df = df[df['code'].isin(dfk['code'])].reset_index(drop=True)
df = df[df["code"].isin(dfk["code"])].reset_index(drop=True)
symbols = [f"{row['code']}#ETF" for _, row in df.iterrows()]
return symbols

if name == "A股指数":
# 指数 https://s0cqcxuy3p.feishu.cn/wiki/KuSAweAAhicvsGk9VPTc1ZWKnAd
df = dc.index_basic(v=2, market='SSE,SZSE', ttl=3600 * 6)
df = dc.index_basic(v=2, market="SSE,SZSE", ttl=3600 * 6)
symbols = [f"{row['code']}#INDEX" for _, row in df.iterrows()]
return symbols

if name == "南华指数":
df = dc.index_basic(v=2, market='NH', ttl=3600 * 6)
symbols = [row['code'] for _, row in df.iterrows()]
df = dc.index_basic(v=2, market="NH", ttl=3600 * 6)
symbols = [row["code"] for _, row in df.iterrows()]
return symbols

if name == "期货主力":
kline = dc.future_klines(trade_date="20240402", ttl=3600 * 6)
return kline['code'].unique().tolist()
return kline["code"].unique().tolist()

if name.upper() == "ALL":
symbols = get_symbols("股票") + get_symbols("ETF")
Expand All @@ -90,12 +99,12 @@ def get_symbols(name, **kwargs):
raise ValueError(f"{name} 分组无法识别,获取标的列表失败!")


def get_min_future_klines(code, sdt, edt, freq='1m'):
def get_min_future_klines(code, sdt, edt, freq="1m"):
"""分段获取期货1分钟K线后合并"""
# dates = pd.date_range(start=sdt, end=edt, freq='1M')
dates = pd.date_range(start=sdt, end=edt, freq='120D')
dates = pd.date_range(start=sdt, end=edt, freq="120D")

dates = [d.strftime('%Y%m%d') for d in dates] + [sdt, edt]
dates = [d.strftime("%Y%m%d") for d in dates] + [sdt, edt]
dates = sorted(list(set(dates)))

rows = []
Expand All @@ -108,25 +117,25 @@ def get_min_future_klines(code, sdt, edt, freq='1m'):
rows.append(df)

df = pd.concat(rows, ignore_index=True)
df.rename(columns={'code': 'symbol'}, inplace=True)
df['dt'] = pd.to_datetime(df['dt'])
df = df.drop_duplicates(subset=['dt', 'symbol'], keep='last')
df.rename(columns={"code": "symbol"}, inplace=True)
df["dt"] = pd.to_datetime(df["dt"])
df = df.drop_duplicates(subset=["dt", "symbol"], keep="last")

if code in ['SFIC9001', 'SFIF9001', 'SFIH9001']:
if code in ["SFIC9001", "SFIF9001", "SFIH9001"]:
# 股指:仅保留 09:31 - 11:30, 13:01 - 15:00
dt1 = datetime.strptime("09:31:00", "%H:%M:%S")
dt2 = datetime.strptime("11:30:00", "%H:%M:%S")
c1 = (df['dt'].dt.time >= dt1.time()) & (df['dt'].dt.time <= dt2.time())
c1 = (df["dt"].dt.time >= dt1.time()) & (df["dt"].dt.time <= dt2.time())

dt3 = datetime.strptime("13:01:00", "%H:%M:%S")
dt4 = datetime.strptime("15:00:00", "%H:%M:%S")
c2 = (df['dt'].dt.time >= dt3.time()) & (df['dt'].dt.time <= dt4.time())
c2 = (df["dt"].dt.time >= dt3.time()) & (df["dt"].dt.time <= dt4.time())

df = df[c1 | c2].copy().reset_index(drop=True)
return df


def get_raw_bars(symbol, freq, sdt, edt, fq='前复权', **kwargs):
def get_raw_bars(symbol, freq, sdt, edt, fq="前复权", **kwargs):
"""获取 CZSC 库定义的标准 RawBar 对象列表
:param symbol: 标的代码
Expand All @@ -142,61 +151,68 @@ def get_raw_bars(symbol, freq, sdt, edt, fq='前复权', **kwargs):
>>> df = coo.get_raw_bars(symbol="000001.SH#INDEX", freq="日线", sdt="2001-01-01", edt="2021-12-31", fq='后复权', raw_bars=False)
"""
freq = czsc.Freq(freq)
raw_bars = kwargs.get('raw_bars', True)
ttl = kwargs.get('ttl', -1)
raw_bars = kwargs.get("raw_bars", True)
ttl = kwargs.get("ttl", -1)

if "SH" in symbol or "SZ" in symbol:
fq_map = {"前复权": "qfq", "后复权": "hfq", "不复权": None}
adj = fq_map.get(fq, None)

code, asset = symbol.split("#")

if freq.value.endswith('分钟'):
df = dc.pro_bar(code=code, sdt=sdt, edt=edt, freq='min', adj=adj, asset=asset[0].lower(), v=2, ttl=ttl)
df = df[~df['dt'].str.endswith("09:30:00")].reset_index(drop=True)
df.rename(columns={'code': 'symbol'}, inplace=True)
df['dt'] = pd.to_datetime(df['dt'])
return czsc.resample_bars(df, target_freq=freq, raw_bars=raw_bars, base_freq='1分钟')
if freq.value.endswith("分钟"):
df = dc.pro_bar(code=code, sdt=sdt, edt=edt, freq="min", adj=adj, asset=asset[0].lower(), v=2, ttl=ttl)
df = df[~df["dt"].str.endswith("09:30:00")].reset_index(drop=True)
df.rename(columns={"code": "symbol"}, inplace=True)
df["dt"] = pd.to_datetime(df["dt"])
return czsc.resample_bars(df, target_freq=freq, raw_bars=raw_bars, base_freq="1分钟")

else:
df = dc.pro_bar(code=code, sdt=sdt, edt=edt, freq='day', adj=adj, asset=asset[0].lower(), v=2, ttl=ttl)
df.rename(columns={'code': 'symbol'}, inplace=True)
df['dt'] = pd.to_datetime(df['dt'])
df = dc.pro_bar(code=code, sdt=sdt, edt=edt, freq="day", adj=adj, asset=asset[0].lower(), v=2, ttl=ttl)
df.rename(columns={"code": "symbol"}, inplace=True)
df["dt"] = pd.to_datetime(df["dt"])
return czsc.resample_bars(df, target_freq=freq, raw_bars=raw_bars)

if symbol.endswith("9001"):
# https://s0cqcxuy3p.feishu.cn/wiki/WLGQwJLWQiWPCZkPV7Xc3L1engg
if fq == "前复权":
logger.warning("期货主力合约暂时不支持前复权,已自动切换为后复权")

freq_rd = '1m' if freq.value.endswith('分钟') else '1d'
if freq.value.endswith('分钟'):
df = get_min_future_klines(code=symbol, sdt=sdt, edt=edt, freq='1m')
df['amount'] = df['vol'] * df['close']
df = df[['symbol', 'dt', 'open', 'close', 'high', 'low', 'vol', 'amount']].copy().reset_index(drop=True)
df['dt'] = pd.to_datetime(df['dt'])
return czsc.resample_bars(df, target_freq=freq, raw_bars=raw_bars, base_freq='1分钟')
freq_rd = "1m" if freq.value.endswith("分钟") else "1d"
if freq.value.endswith("分钟"):
df = get_min_future_klines(code=symbol, sdt=sdt, edt=edt, freq="1m")
if "amount" not in df.columns:
df["amount"] = df["vol"] * df["close"]

df = df[["symbol", "dt", "open", "close", "high", "low", "vol", "amount"]].copy().reset_index(drop=True)
df["dt"] = pd.to_datetime(df["dt"])
return czsc.resample_bars(df, target_freq=freq, raw_bars=raw_bars, base_freq="1分钟")

else:
df = dc.future_klines(code=symbol, sdt=sdt, edt=edt, freq=freq_rd, ttl=ttl)
df.rename(columns={'code': 'symbol'}, inplace=True)
df['amount'] = df['vol'] * df['close']
df = df[['symbol', 'dt', 'open', 'close', 'high', 'low', 'vol', 'amount']].copy().reset_index(drop=True)
df['dt'] = pd.to_datetime(df['dt'])
df.rename(columns={"code": "symbol"}, inplace=True)
if "amount" not in df.columns:
df["amount"] = df["vol"] * df["close"]

df = df[["symbol", "dt", "open", "close", "high", "low", "vol", "amount"]].copy().reset_index(drop=True)
df["dt"] = pd.to_datetime(df["dt"])
return czsc.resample_bars(df, target_freq=freq, raw_bars=raw_bars)

if symbol.endswith(".NH"):
if freq != Freq.D:
raise ValueError("南华指数只支持日线数据")
df = dc.nh_daily(code=symbol, sdt=sdt, edt=edt, ttl=ttl)
df = dc.nh_daily(code=symbol, sdt=sdt, edt=edt, ttl=ttl, v=2)
df.rename(columns={"code": "symbol", "volume": "vol"}, inplace=True)
df["dt"] = pd.to_datetime(df["dt"])
return czsc.resample_bars(df, target_freq=freq, raw_bars=raw_bars)

raise ValueError(f"symbol {symbol} 无法识别,获取数据失败!")


@czsc.disk_cache(path=cache_path, ttl=-1)
def stocks_daily_klines(sdt='20170101', edt="20240101", **kwargs):
def stocks_daily_klines(sdt="20170101", edt="20240101", **kwargs):
"""获取全市场A股的日线数据"""
adj = kwargs.get('adj', 'hfq')
adj = kwargs.get("adj", "hfq")
sdt = pd.to_datetime(sdt).year
edt = pd.to_datetime(edt).year
years = [str(year) for year in range(sdt, edt + 1)]
Expand All @@ -208,18 +224,18 @@ def stocks_daily_klines(sdt='20170101', edt="20240101", **kwargs):
res.append(kline)

dfk = pd.concat(res, ignore_index=True)
dfk['dt'] = pd.to_datetime(dfk['dt'])
dfk = dfk.sort_values(['code', 'dt'], ascending=True).reset_index(drop=True)
if kwargs.get('exclude_bj', True):
dfk = dfk[~dfk['code'].str.endswith(".BJ")].reset_index(drop=True)
dfk["dt"] = pd.to_datetime(dfk["dt"])
dfk = dfk.sort_values(["code", "dt"], ascending=True).reset_index(drop=True)
if kwargs.get("exclude_bj", True):
dfk = dfk[~dfk["code"].str.endswith(".BJ")].reset_index(drop=True)

nxb = kwargs.get('nxb', [1, 2, 5])
nxb = kwargs.get("nxb", [1, 2, 5])
if nxb:
rows = []
for _, dfg in tqdm(dfk.groupby('code'), desc="计算NXB收益率", ncols=80, colour='green'):
czsc.update_nbars(dfg, numbers=nxb, move=1, price_col='open')
for _, dfg in tqdm(dfk.groupby("code"), desc="计算NXB收益率", ncols=80, colour="green"):
czsc.update_nbars(dfg, numbers=nxb, move=1, price_col="open")
rows.append(dfg)
dfk = pd.concat(rows, ignore_index=True)

dfk = dfk.rename(columns={'code': 'symbol'})
dfk = dfk.rename(columns={"code": "symbol"})
return dfk
Loading

0 comments on commit 972f960

Please sign in to comment.