Skip to content

Commit

Permalink
0.9.24 update
Browse files Browse the repository at this point in the history
  • Loading branch information
zengbin93 committed Jul 15, 2023
1 parent b86525c commit 59f59cd
Show file tree
Hide file tree
Showing 5 changed files with 33 additions and 7 deletions.
2 changes: 1 addition & 1 deletion czsc/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
from czsc.utils import CrossSectionalPerformance
from czsc.sensors import holds_concepts_effect, CTAResearch, EventMatchSensor
from czsc.utils.signal_analyzer import SignalAnalyzer, SignalPerformance
from czsc.utils.stats import daily_performance, net_value_stats
from czsc.utils.stats import daily_performance, net_value_stats, subtract_fee


__version__ = "0.9.24"
Expand Down
2 changes: 1 addition & 1 deletion czsc/connectors/qmt_connector.py
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ def get_kline(symbol, period, start_time, end_time, count=-1, dividend_type='fro
return format_stock_kline(df, freq=freq_map[period])


def get_raw_bars(symbol, freq, sdt, edt, fq='前复权', **kwargs):
def get_raw_bars(symbol, freq, sdt, edt, fq='前复权', **kwargs) -> List[RawBar]:
"""获取 CZSC 库定义的标准 RawBar 对象列表
:param symbol: 标的代码
Expand Down
5 changes: 4 additions & 1 deletion czsc/sensors/event.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
describe: Event 相关的传感器
"""
import os
import shutil
import pandas as pd
from copy import deepcopy
from loguru import logger
Expand Down Expand Up @@ -43,7 +44,9 @@ def __init__(self, events: List[Union[Dict[str, Any], Event]], symbols: List[str
self.events_map = {event.name: event for event in self.events}
self.events_name = [event.name for event in self.events]
self.results_path = kwargs.pop("results_path")
if os.path.exists(self.results_path):
self.refresh = kwargs.pop("refresh", False)
if os.path.exists(self.results_path) and self.refresh:
shutil.rmtree(self.results_path)
logger.warning(f"文件夹 {self.results_path} 已存在,程序将覆盖该文件夹下的所有文件")
os.makedirs(self.results_path, exist_ok=True)
save_json({e.name: e.dump() for e in self.events}, os.path.join(self.results_path, "events.json"))
Expand Down
2 changes: 1 addition & 1 deletion czsc/utils/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
from .plotly_plot import KlineChart
from .trade import cal_trade_price, update_nbars, update_bbars, update_tbars
from .cross import CrossSectionalPerformance
from .stats import daily_performance, net_value_stats
from .stats import daily_performance, net_value_stats, subtract_fee


sorted_freqs = ['Tick', '1分钟', '5分钟', '15分钟', '30分钟', '60分钟', '日线', '周线', '月线', '季线', '年线']
Expand Down
29 changes: 26 additions & 3 deletions czsc/utils/stats.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,28 @@
import pandas as pd


def subtract_fee(df, fee=1):
"""依据单品种持仓信号扣除手续费"""
assert 'dt' in df.columns, 'dt 列必须存在'
assert 'pos' in df.columns, 'pos 列必须存在'
assert all(x in [0, 1, -1] for x in df['pos'].unique()), "pos 列的值必须是 0, 1, -1 中的一个"

if 'n1b' not in df.columns:
assert 'price' in df.columns, '当n1b列不存在时,price 列必须存在'
df['n1b'] = (df['price'].shift(-1) / df['price'] - 1) * 10000

df['date'] = df['dt'].dt.date
df['edge_pre_fee'] = df['pos'] * df['n1b']
df['edge_post_fee'] = df['pos'] * df['n1b']

# 扣费规则, 开仓扣费在第一个持仓K线上,平仓扣费在最后一个持仓K线上
open_pos = (df['pos'].shift() != df['pos']) & (df['pos'] != 0)
exit_pos = (df['pos'].shift(-1) != df['pos']) & (df['pos'] != 0)
df.loc[open_pos, 'edge_post_fee'] = df.loc[open_pos, 'edge_post_fee'] - fee
df.loc[exit_pos, 'edge_post_fee'] = df.loc[exit_pos, 'edge_post_fee'] - fee
return df


def daily_performance(daily_returns):
"""计算日收益数据的年化收益率、夏普比率、最大回撤、卡玛比率
Expand All @@ -27,15 +49,16 @@ def daily_performance(daily_returns):
cum_returns = np.cumprod(1 + daily_returns)
max_drawdown = np.max(np.maximum.accumulate(cum_returns) - cum_returns) / np.max(cum_returns)
kama = annual_returns / max_drawdown if max_drawdown != 0 else 10
win_pct = len(daily_returns[daily_returns > 0]) / len(daily_returns)
return {
"年化": round(annual_returns, 4),
"夏普": round(sharpe_ratio, 2),
"最大回撤": round(max_drawdown, 4),
"卡玛": round(kama, 2)
"回撤": round(max_drawdown, 4),
"卡玛": round(kama, 2),
"胜率": round(win_pct, 4),
}



def net_value_stats(nv: pd.DataFrame, exclude_zero: bool = False, sub_cost=True) -> dict:
"""统计净值曲线的年化收益、夏普等
Expand Down

0 comments on commit 59f59cd

Please sign in to comment.