Skip to content

Commit

Permalink
0.9.38 update docs
Browse files Browse the repository at this point in the history
  • Loading branch information
zengbin93 committed Dec 3, 2023
1 parent 6647882 commit 518bc9a
Show file tree
Hide file tree
Showing 9 changed files with 541 additions and 33 deletions.
27 changes: 26 additions & 1 deletion czsc/objects.py
Original file line number Diff line number Diff line change
Expand Up @@ -1058,6 +1058,31 @@ def evaluate(self, trade_dir: str = "多空") -> dict:
def update(self, s: dict):
"""更新持仓状态
函数执行逻辑:
- 首先,检查最新信号的时间是否在上次信号之前,如果是则打印警告信息并返回。
- 初始化一些变量,包括操作类型(op)和操作描述(op_desc)。
- 遍历所有的事件,检查是否与最新信号匹配。如果匹配,则记录操作类型和操作描述,并跳出循环。
- 提取最新信号的相关信息,包括交易对符号、时间、价格和成交量。
- 更新持仓状态的结束时间为最新信号的时间。
- 如果操作类型是开仓(LO或SO),更新最后一个事件的信息。
- 定义一个内部函数__create_operate,用于创建操作记录。
- 根据操作类型更新仓位和操作记录。
- 如果操作类型是LO(开多),检查是否满足开仓条件,如果满足则开多仓,否则只平空仓。
- 如果操作类型是SO(开空),检查是否满足开仓条件,如果满足则开空仓,否则只平多仓。
- 如果当前持仓为多仓,进行多头出场的判断:
- 如果操作类型是LE(平多),平多仓。
- 如果当前价格相对于最后一个事件的价格的收益率小于止损阈值,平多仓。
- 如果当前成交量相对于最后一个事件的成交量的增加量大于超时阈值,平多仓。
- 如果当前持仓为空仓,进行空头出场的判断:
- 如果操作类型是SE(平空),平空仓。
- 如果当前价格相对于最后一个事件的价格的收益率小于止损阈值,平空仓。
- 如果当前成交量相对于最后一个事件的成交量的增加量大于超时阈值,平空仓。
- 将当前持仓状态和价格记录到持仓列表中。
:param s: 最新信号字典
:return:
"""
Expand Down Expand Up @@ -1091,7 +1116,7 @@ def update(self, s: dict):
def __create_operate(_op, _op_desc):
self.pos_changed = True
return {
"symbol": self.symbol,
"symbol": symbol,
"dt": dt,
"bid": bid,
"price": price,
Expand Down
42 changes: 41 additions & 1 deletion czsc/sensors/event.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,16 @@ def __init__(self, events: List[Union[Dict[str, Any], Event]], symbols: List[str
self.csc = df

def _get_signals_config(self):
"""获取所有事件的信号配置,并将其合并为一个不包含重复项的列表。
该列表包含了所有事件所需的信号计算和解析规则,以便于后续的事件匹配过程。
1. 创建一个空列表 config,用于存储所有的信号配置。
2. 遍历 self.events 中的所有事件(Event 对象)。对于每个事件,调用其 get_signals_config 方法,
传入 signals_module 参数,并将返回值(即该事件的信号配置)添加到 config 列表中。
3. 通过 list comprehension 生成一个新的列表 config。对 config 列表中的每个字典 d
使用 tuple(d.items()) 转换为元组,然后将这些元组转换回 dict 并加入新列表中。
4. 返回处理后的 config 列表。
"""
config = []
for event in self.events:
_c = event.get_signals_config(signals_module=self.signals_module)
Expand All @@ -99,7 +109,28 @@ def _get_signals_config(self):
return config

def _single_symbol(self, symbol):
"""单个symbol的事件匹配"""
"""单个symbol的事件匹配
对单个标的(symbol)进行事件匹配。它首先获取 K 线数据,然后生成 CZSC 信号,接着遍历每个事件并计算匹配情况,
最后整理数据框并返回。如果在过程中遇到问题,则记录错误并返回一个空 DataFrame。
函数执行逻辑:
1. 调用 self.read_bars 方法读取指定 symbol、频率(self.base_freq)、开始时间(self.bar_sdt)
和结束时间(self.edt)的 K 线数据,并将返回值赋给 bars。
2. 使用 generate_czsc_signals 函数生成 CZSC 信号。这里传入了 bars、复制后的
signals_config(以防止修改原始配置)、开始时间(self.sdt)以及 df=False(表示返回一个字典列表而非 DataFrame 对象)。
3. 将上一步生成的信号转换为 DataFrame 并保存到 sigs 变量中。
4. 创建一个新的 events 复制品(以防止修改原始事件列表),并创建一个空列表 new_cols,用于存储新添加的列名。
5. 遍历新的 events 列表,对于每个 event:
a. 获取 event 的名称 e_name。
b. 使用 apply 函数应用 is_match 方法来判断每行数据是否与该事件相匹配。
结果是一个布尔值和一个 float 值(表示匹配得分),它们分别被保存为 e_name 和 f'{e_name}_F' 列。
c. 将这两个新列名添加到 new_cols 列表中。
6. 在 sigs 数据框中添加一列 n1b,表示涨跌幅。
7. 最后,重新组织 sigs 数据框的列顺序,使其包含以下列:symbol、dt、open、close、high、low、vol、amount、n1b 以及所有新添加的列。
"""
try:
bars = self.read_bars(symbol, freq=self.base_freq, sdt=self.bar_sdt, edt=self.edt, **self.kwargs)
sigs = generate_czsc_signals(bars, deepcopy(self.signals_config), sdt=self.sdt, df=False)
Expand Down Expand Up @@ -139,6 +170,15 @@ def get_event_csc(self, event_name: str):
csc = cross section count,表示截面匹配次数
函数执行逻辑:
1. 创建一个 self.data 的副本 df。
2. 在 df 中筛选出 event_name 列等于 1 的行。
3. 使用 groupby 方法按 symbol 和 dt 对筛选后的数据进行分组,并计算 event_name 列的总和。
结果将形成一个新的 DataFrame,其中索引为 (symbol, dt) 组合,只有一个列 event_name,表示每个组合的匹配次数。
4. 再次使用 groupby 方法按 dt 对上一步的结果进行分组,并计算 event_name 列的总和。这次得到的新 DataFrame
只有一个列 event_name,表示在每个时间点所有标的的事件匹配总数。
:param event_name: 事件名称
:return: DataFrame
"""
Expand Down
15 changes: 15 additions & 0 deletions czsc/sensors/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,21 @@ def holds_concepts_effect(holds: pd.DataFrame, concepts: dict, top_n=20, min_n=3
原理概述:在选股时,如果股票的概念板块与组合中的其他股票的概念板块有重合,那么这个股票的表现会更好。
函数计算逻辑:
1. 如果kwargs中存在'copy'键且对应值为True,则将holds进行复制。
2. 为holds添加'概念板块'列,该列的值是holds中'symbol'列对应的股票的概念板块列表,如果没有对应的概念板块则填充为空。
3. 添加'概念数量'列,该列的值是每个股票的概念板块数量。
4. 从holds中筛选出概念数量大于0的行,赋值给holds。
5. 创建空列表new_holds和空字典dt_key_concepts。
6. 对holds按照'dt'进行分组,遍历每个分组,计算板块效应。
a. 计算密集出现的概念,选取出现次数最多的前top_n个概念,赋值给key_concepts列表。
b. 将日期dt和对应的key_concepts存入dt_key_concepts字典。
c. 计算在密集概念中出现次数超过min_n的股票,将符合条件的股票添加到new_holds列表中。
7. 使用pd.concat将new_holds中的DataFrame进行合并,忽略索引,赋值给dfh。
8. 创建DataFrame dfk,其中包含日期(dt)和对应的强势概念(key_concepts)。
9. 返回dfh和dfk。
:param holds: 组合股票池数据,样例:
=================== ========= ==========
Expand Down
65 changes: 56 additions & 9 deletions czsc/strategies.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,19 +79,30 @@ def positions(self) -> List[Position]:
def init_bar_generator(self, bars: List[RawBar], **kwargs):
"""使用策略定义初始化一个 BarGenerator 对象
函数执行逻辑:
- 该方法的目的是使用策略定义初始化一个BarGenerator对象。BarGenerator是用于生成K线数据的类。
- 参数bars表示基础周期的K线数据,**kwargs用于接收额外的关键字参数。
- 首先,方法获取了基础K线的频率,并检查了是否已经有一个初始化好的BarGenerator对象传入。
- 然后,根据基础频率是否在排序后的频率列表中,确定要使用的频率列表。
- 如果没有传入BarGenerator对象,则根据传入的基础K线数据和其他参数创建一个新的BarGenerator对象,
并使用部分K线数据初始化它。余下的K线数据将用于trader的初始化区间。
- 如果传入了BarGenerator对象,则会做一些断言检查,确保传入的基础K线数据与已有的BarGenerator对象的基础周期一致,
并且BarGenerator的end_dt是datetime类型。然后,筛选出在BarGenerator的end_dt之后的K线数据。
- 最后,返回BarGenerator对象和余下的K线数据。
:param bars: 基础周期K线
:param kwargs:
bg 已经初始化好的BarGenerator对象,如果传入了bg,则忽略sdt和n参数
sdt 初始化开始日期
n 初始化最小K线数量
:return:
"""
base_freq = str(bars[0].freq.value)
bg: BarGenerator = kwargs.get("bg", None)
if base_freq in self.sorted_freqs:
freqs = self.sorted_freqs[1:]
else:
freqs = self.sorted_freqs
freqs = self.sorted_freqs[1:] if base_freq in self.sorted_freqs else self.sorted_freqs

if bg is None:
uni_times = sorted(list({x.dt.strftime("%H:%M") for x in bars}))
Expand Down Expand Up @@ -125,11 +136,20 @@ def init_trader(self, bars: List[RawBar], **kwargs) -> CzscTrader:
**注意:** 这里会将所有持仓策略在 sdt 之后的交易信号计算出来并缓存在持仓策略实例内部,所以初始化的过程本身也是回测的过程。
函数执行逻辑:
- 首先,它通过调用init_bar_generator方法获取已经初始化好的BarGenerator对象和余下的K线数据。
- 然后,它创建一个CzscTrader对象,将BarGenerator对象、持仓策略的深拷贝、交易信号配置的深拷贝等参数传递给CzscTrader的构造函数。
- 接着,使用余下的K线数据对CzscTrader对象进行初始化,通过调用trader.on_bar(bar)方法处理每一根K线数据。
- 最后,返回初始化完成的CzscTrader对象。
:param bars: 基础周期K线
:param kwargs:
bg 已经初始化好的BarGenerator对象,如果传入了bg,则忽略sdt和n参数
sdt 初始化开始日期
n 初始化最小K线数量
:return: 完成策略初始化后的 CzscTrader 对象
"""
bg, bars2 = self.init_bar_generator(bars, **kwargs)
Expand All @@ -152,7 +172,7 @@ def dummy(self, sigs: List[dict], **kwargs) -> CzscTrader:
sleep_time = kwargs.get("sleep_time", 0)
sleep_step = kwargs.get("sleep_step", 1000)

trader = CzscTrader(positions=deepcopy(self.positions)) # type: ignore
trader = CzscTrader(positions=deepcopy(self.positions)) # type: ignore
for i, sig in tqdm(enumerate(sigs), desc=f"回测 {self.symbol} {self.sorted_freqs}"):
trader.on_sig(sig)

Expand All @@ -164,12 +184,28 @@ def dummy(self, sigs: List[dict], **kwargs) -> CzscTrader:
def replay(self, bars: List[RawBar], res_path, **kwargs):
"""交易策略交易过程回放
函数执行逻辑:
- 该方法用于交易策略交易过程的回放。它接受基础周期的K线数据、结果目录以及额外的关键字参数作为输入。
- 首先,它检查refresh参数,如果为True,则使用shutil.rmtree删除已存在的结果目录。
- 然后,它检查结果目录是否已存在,并且是否允许覆盖。如果目录已存在且不允许覆盖,则记录一条警告信息并返回。
- 通过调用os.makedirs创建结果目录,确保目录的存在。
- 接着,调用init_bar_generator方法初始化BarGenerator对象,并进行相关的初始化操作。
- 创建一个CzscTrader对象,并将初始化好的BarGenerator对象、持仓策略的深拷贝、交易信号配置的深拷贝等参数传递给CzscTrader的构造函数。
- 为每个持仓策略创建相应的目录。
- 遍历K线数据,调用trader.on_bar(bar)方法处理每一根K线数据。
- 在每根K线数据处理完成后,检查每个持仓策略是否有操作,并且操作的时间是否与当前K线的时间一致。
如果有操作,则生成相应的HTML文件名,并调用trader.take_snapshot(file_html)方法生成交易快照。
- 最后,遍历每个持仓策略,记录其评估信息,包括多空合并表现、多头表现、空头表现等。
:param bars: 基础周期K线
:param res_path: 结果目录
:param kwargs:
bg 已经初始化好的BarGenerator对象,如果传入了bg,则忽略sdt和n参数
sdt 初始化开始日期
n 初始化最小K线数量
bg 已经初始化好的BarGenerator对象,如果传入了bg,则忽略sdt和n参数
sdt 初始化开始日期
n 初始化最小K线数量
refresh 是否刷新结果目录
:return:
"""
if kwargs.get("refresh", False):
Expand Down Expand Up @@ -294,7 +330,7 @@ def save_positions(self, path):
:return: None
"""
os.makedirs(path, exist_ok=True)
for pos in self.positions: # type: ignore
for pos in self.positions: # type: ignore
pos_ = pos.dump()
pos_.pop("symbol")
hash_code = hashlib.md5(str(pos_).encode()).hexdigest()
Expand Down Expand Up @@ -322,6 +358,17 @@ def load_positions(self, files: List, check=True) -> List[Position]:
class CzscJsonStrategy(CzscStrategyBase):
"""仅传入Json配置的Positions就完成策略创建
执行逻辑:
1. 定义CzscJsonStrategy类,并继承自CzscStrategyBase。这个类可以通过仅传入Json配置的Positions来完成策略创建。
2. 类中定义了一个名为positions的属性,使用@property装饰器将其标记为只读属性。
3. 在positions属性的getter方法中,执行以下操作:
- 从self.kwargs字典中获取键为"files_position"的值,并将其赋值给变量files。
这里的self.kwargs可能是通过在实例化该类时传入的参数或其他方式设置的一个字典,其中包含了策略配置文件的路径列表。
- 使用self.kwargs.get方法获取键为"check_position"的值,并设置默认值为True,将其赋值给变量check。这个值用于确定是否对JSON持仓策略进行MD5校验。
- 调用self.load_positions(files, check)方法,并返回其结果。这个方法可能是从父类CzscStrategyBase中继承的方法,
用于从配置文件中加载持仓策略。将文件列表和校验标志作为参数传递给该方法,并返回加载的持仓策略列表。
必须参数:
files_position: 以 json 文件配置的策略,每个json文件对应一个持仓策略配置
check_position: 是否对 json 持仓策略进行 MD5 校验,默认为 True
Expand Down
Loading

0 comments on commit 518bc9a

Please sign in to comment.