Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

V0.9.58 更新一批代码 #211

Merged
merged 19 commits into from
Aug 31, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .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.57 ]
branches: [ master, V0.9.58 ]
pull_request:
branches: [ master ]

Expand Down
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,11 @@

>为什么要去了解其他理论,就是这些理论操作者的行为模式,将构成以后我们猎杀的对象,他们操作模式的缺陷,就是以后猎杀他们的最好武器,这就如同学独孤九剑,必须学会发现所有派别招数的缺陷,这也是本ID理论学习中一个极为关键的步骤。

>真正的预测,就是不测而测。所有预测的基础,就是分类,把所有可能的情况进行完全分类。有人可能说,分类以后,把不可能的排除,最后一个结果就是精确的。
>这是脑子锈了的想法,任何的排除,等价于一次预测,每排除一个分类,按概率的乘法原则,就使得最后的所谓精确变得越不精确,最后还是逃不掉概率的套子。
>对于预测分类的唯一正确原则就是不进行任何排除,而是要严格分清每种情况的边界条件。任何的分类,其实都等价于一个分段函数,就是要把这分段函数的边界条件确定清楚。
>边界条件分段后,就要确定一旦发生哪种情况就如何操作,也就是把操作也同样给分段化了。然后,把所有情况交给市场本身,让市场自己去当下选择。
>所有的操作,其实都是根据不同分段边界的一个结果,只是每个人的分段边界不同而已。因此,问题不是去预测什么,而是确定分段边界。

## 知识星球

Expand Down
6 changes: 4 additions & 2 deletions czsc/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -202,13 +202,15 @@
from czsc.eda import (
remove_beta_effects, vwap, twap,
cross_sectional_strategy,
judge_factor_direction,
monotonicity,
)


__version__ = "0.9.57"
__version__ = "0.9.58"
__author__ = "zengbin93"
__email__ = "[email protected]"
__date__ = "20240726"
__date__ = "20240808"


def welcome():
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 @@ -138,7 +138,7 @@ def start_qmt_exe(acc, pwd, qmt_exe, title, max_retry=6, **kwargs):

wait_seconds = kwargs.get("wait_seconds", 6)
i = 0
while not find_exe_window(acc):
while not find_exe_window(title):
if i > max_retry:
logger.warning(f"QMT连续{i}次尝试依旧无法启动,请人工检查!")
break
Expand Down
54 changes: 48 additions & 6 deletions czsc/eda.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,15 +39,17 @@ def remove_beta_effects(df, **kwargs):
- factor: str, 因子列名
- betas: list, beta 列名列表
- linear_model: str, 线性模型,可选 ridge、linear 或 lasso
- linear_model_params: dict, 线性模型参数, 默认为空, 需要传入字典,根据模型不同参数不同

:return: DataFrame
"""

linear_model = kwargs.get("linear_model", "ridge")
linear_model_params = kwargs.get("linear_model_params", {})
linear = {
"ridge": Ridge(),
"linear": LinearRegression(),
"lasso": Lasso(),
"ridge": Ridge,
"linear": LinearRegression,
"lasso": Lasso,
}
assert linear_model in linear.keys(), "linear_model 参数必须为 ridge、linear 或 lasso"
Model = linear[linear_model]
Expand All @@ -71,7 +73,7 @@ def remove_beta_effects(df, **kwargs):

x = dfg[betas].values
y = dfg[factor].values
model = Model().fit(x, y)
model = Model(**linear_model_params).fit(x, y)
dfg[factor] = y - model.predict(x)
rows.append(dfg)

Expand Down Expand Up @@ -113,7 +115,47 @@ def cross_sectional_strategy(df, factor, **kwargs):

dfa = dfg.sort_values(factor, ascending=False).head(long_num)
dfb = dfg.sort_values(factor, ascending=True).head(short_num)
df.loc[dfa.index, "weight"] = 1 / long_num
df.loc[dfb.index, "weight"] = -1 / short_num
if long_num > 0:
df.loc[dfa.index, "weight"] = 1 / long_num
if short_num > 0:
df.loc[dfb.index, "weight"] = -1 / short_num

return df


def judge_factor_direction(df: pd.DataFrame, factor, target='n1b', by='symbol', **kwargs):
"""判断因子的方向,正向还是反向

:param df: pd.DataFrame, 数据源,必须包含 symbol, dt, target, factor 列
:param factor: str, 因子名称
:param target: str, 目标名称,默认为 n1b,表示下一根K线的涨跌幅
:param by: str, 分组字段,默认为 symbol,表示按品种分组(时序);也可以按 dt 分组,表示按时间分组(截面)
:param kwargs: dict, 其他参数
- method: str, 相关系数计算方法,默认为 pearson,可选 pearson, kendall, spearman
:return: str, positive or negative
"""
assert by in df.columns, f"数据中不存在 {by} 字段"
assert factor in df.columns, f"数据中不存在 {factor} 字段"
assert target in df.columns, f"数据中不存在 {target} 字段"

if by == "dt" and df['symbol'].nunique() < 2:
raise ValueError("品种数量过少,无法在时间截面上计算因子有效性方向")

if by == "symbol" and df['dt'].nunique() < 2:
raise ValueError("时间序列数据量过少,无法在品种上计算因子有效性方向")

method = kwargs.get("method", "pearson")
dfc = df.groupby(by)[[factor, target]].corr(method=method).unstack().iloc[:, 1].reset_index()
return "positive" if dfc[factor].mean().iloc[0] >= 0 else "negative"


def monotonicity(sequence):
"""计算序列的单调性

原理:计算序列与自然数序列的相关系数,系数越接近1,表示单调递增;系数越接近-1,表示单调递减;接近0表示无序

:param sequence: list, tuple 序列
:return: float, 单调性系数
"""
from scipy.stats import spearmanr
return spearmanr(sequence, range(len(sequence)))[0]
10 changes: 5 additions & 5 deletions czsc/fsa/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
author: zengbin93
email: [email protected]
create_dt: 2022/12/16 19:37
describe:
describe:
"""

import requests
Expand Down Expand Up @@ -36,7 +36,7 @@ def push_text(text: str, key: str) -> None:
logger.error(f"推送消息失败: {e}")


def push_card(card: str, key: str) -> None:
def push_card(card: dict, key: str) -> None:
"""使用自定义机器人推送卡片消息到飞书群聊

如何在群组中使用机器人:
Expand Down Expand Up @@ -150,7 +150,7 @@ def update_spreadsheet(df: pd.DataFrame, spreadsheet_token: str, sheet_id: str,

获取 sheet_id - https://open.feishu.cn/document/server-docs/docs/sheets-v3/spreadsheet-sheet/query?appId=cli_a3077015cc39500e

:param df: datafream内容
:param df: dataframe内容
:param spreadsheet_token: 表格对应的token,url获取
:param sheet_id: 工作表的id
:param kwargs:
Expand All @@ -175,6 +175,6 @@ def update_spreadsheet(df: pd.DataFrame, spreadsheet_token: str, sheet_id: str,
else:
logger.error(b)
return 0
except Exception:
logger.exception("更新飞书表格失败")
except Exception as e:
logger.exception(f"更新飞书表格失败: {e}")
return 0
4 changes: 4 additions & 0 deletions czsc/fsa/bi_table.py
Original file line number Diff line number Diff line change
Expand Up @@ -725,6 +725,10 @@ def read_table(self, table_id, **kwargs):
rows = []
res = self.list_records(table_id, **kwargs)["data"]
total = res["total"]

if total == 0:
return pd.DataFrame()

rows.extend(res["items"])
while res["has_more"]:
res = self.list_records(table_id, page_token=res["page_token"], **kwargs)["data"]
Expand Down
8 changes: 7 additions & 1 deletion czsc/traders/weight_backtest.py
Original file line number Diff line number Diff line change
Expand Up @@ -565,7 +565,13 @@ def backtest(self, n_jobs=1):
dfw = self.dfw.copy()
long_rate = dfw[dfw["weight"] > 0].shape[0] / dfw.shape[0]
short_rate = dfw[dfw["weight"] < 0].shape[0] / dfw.shape[0]
stats.update({"多头占比": long_rate, "空头占比": short_rate})
stats.update({"多头占比": round(long_rate, 4), "空头占比": round(short_rate, 4)})

alpha = self.alpha.copy()
stats["与基准相关性"] = round(alpha["策略"].corr(alpha["基准"]), 4)
alpha_short = alpha[alpha["基准"] < 0].copy()
stats["与基准空头相关性"] = round(alpha_short["策略"].corr(alpha_short["基准"]), 4)
stats["品种数量"] = len(symbols)

res["绩效评价"] = stats
return res
Expand Down
Loading
Loading