313 lines
11 KiB
Python
313 lines
11 KiB
Python
"""
|
||
筹码分布因子 - 使用Polars实现
|
||
包含筹码集中度、分布偏度、浮筹比例等相关因子计算
|
||
"""
|
||
|
||
import polars as pl
|
||
import numpy as np
|
||
from typing import Dict, List, Optional, Any
|
||
from operator_framework import StockWiseOperator, OperatorConfig
|
||
|
||
|
||
class ChipConcentrationOperator(StockWiseOperator):
|
||
"""筹码集中度算子"""
|
||
|
||
def __init__(self):
|
||
config = OperatorConfig(
|
||
name="chip_concentration",
|
||
description="筹码集中度",
|
||
required_columns=['cost_95pct', 'cost_5pct', 'close'],
|
||
output_columns=['chip_concentration_range'],
|
||
parameters={}
|
||
)
|
||
super().__init__(config)
|
||
|
||
def apply_stock(self, stock_df: pl.DataFrame, **kwargs) -> pl.DataFrame:
|
||
"""计算筹码集中度"""
|
||
epsilon = 1e-8
|
||
|
||
# 计算筹码集中度范围,相对于当前价格标准化
|
||
concentration_range = (pl.col('cost_95pct') - pl.col('cost_5pct')) / (pl.col('close') + epsilon)
|
||
|
||
return stock_df.with_columns(concentration_range.alias('chip_concentration_range'))
|
||
|
||
|
||
class ChipSkewnessOperator(StockWiseOperator):
|
||
"""筹码分布偏度算子"""
|
||
|
||
def __init__(self):
|
||
config = OperatorConfig(
|
||
name="chip_skewness",
|
||
description="筹码分布偏度",
|
||
required_columns=['weight_avg', 'cost_50pct'],
|
||
output_columns=['chip_skewness'],
|
||
parameters={}
|
||
)
|
||
super().__init__(config)
|
||
|
||
def apply_stock(self, stock_df: pl.DataFrame, **kwargs) -> pl.DataFrame:
|
||
"""计算筹码分布偏度"""
|
||
epsilon = 1e-8
|
||
|
||
# 计算偏度:(加权平均成本 - 中位数成本) / 中位数成本
|
||
skewness = (pl.col('weight_avg') - pl.col('cost_50pct')) / (pl.col('cost_50pct') + epsilon)
|
||
|
||
return stock_df.with_columns(skewness.alias('chip_skewness'))
|
||
|
||
|
||
class FloatingChipProxyOperator(StockWiseOperator):
|
||
"""浮筹比例代理算子"""
|
||
|
||
def __init__(self):
|
||
config = OperatorConfig(
|
||
name="floating_chip_proxy",
|
||
description="浮筹比例代理",
|
||
required_columns=['close', 'cost_15pct', 'winner_rate'],
|
||
output_columns=['floating_chip_proxy'],
|
||
parameters={}
|
||
)
|
||
super().__init__(config)
|
||
|
||
def apply_stock(self, stock_df: pl.DataFrame, **kwargs) -> pl.DataFrame:
|
||
"""计算浮筹比例代理"""
|
||
# 计算价格与15%成本线的距离
|
||
price_dist_cost15 = (pl.col('close') - pl.col('cost_15pct')) / pl.col('close')
|
||
|
||
# 计算浮筹代理:获利盘比例 * max(0, 价格距离)
|
||
floating_proxy = pl.col('winner_rate') * pl.max_horizontal(0, price_dist_cost15)
|
||
|
||
return stock_df.with_columns(floating_proxy.alias('floating_chip_proxy'))
|
||
|
||
|
||
class CostSupportChangeOperator(StockWiseOperator):
|
||
"""成本支撑强度变化算子"""
|
||
|
||
def __init__(self, n: int = 1):
|
||
config = OperatorConfig(
|
||
name=f"cost_support_change_{n}",
|
||
description=f"{n}日成本支撑强度变化",
|
||
required_columns=['cost_15pct'],
|
||
output_columns=[f'cost_support_15pct_change_{n}'],
|
||
parameters={'n': n}
|
||
)
|
||
super().__init__(config)
|
||
self.n = n
|
||
|
||
def apply_stock(self, stock_df: pl.DataFrame, **kwargs) -> pl.DataFrame:
|
||
"""计算成本支撑强度变化"""
|
||
# 计算百分比变化
|
||
pct_change = pl.col('cost_15pct').pct_change(self.n) * 100
|
||
|
||
return stock_df.with_columns(pct_change.alias(f'cost_support_15pct_change_{self.n}'))
|
||
|
||
|
||
class WinnerPriceZoneOperator(StockWiseOperator):
|
||
"""获利盘压力/支撑区分类算子"""
|
||
|
||
def __init__(self):
|
||
config = OperatorConfig(
|
||
name="winner_price_zone",
|
||
description="获利盘压力/支撑区分类",
|
||
required_columns=['close', 'cost_85pct', 'cost_15pct', 'cost_50pct', 'winner_rate'],
|
||
output_columns=['cat_winner_price_zone'],
|
||
parameters={}
|
||
)
|
||
super().__init__(config)
|
||
|
||
def apply_stock(self, stock_df: pl.DataFrame, **kwargs) -> pl.DataFrame:
|
||
"""计算获利盘压力/支撑区分类"""
|
||
# 定义条件
|
||
conditions = [
|
||
# 1: 高风险区 (高位 & 高获利盘)
|
||
(pl.col('close') > pl.col('cost_85pct')) & (pl.col('winner_rate') > 0.8),
|
||
# 2: 低潜力区 (低位 & 低获利盘)
|
||
(pl.col('close') < pl.col('cost_15pct')) & (pl.col('winner_rate') < 0.2),
|
||
# 3: 中上获利区 (中高位 & 多数获利)
|
||
(pl.col('close') > pl.col('cost_50pct')) & (pl.col('winner_rate') > 0.5),
|
||
# 4: 中下亏损区 (中低位 & 多数亏损)
|
||
(pl.col('close') < pl.col('cost_50pct')) & (pl.col('winner_rate') < 0.5),
|
||
]
|
||
|
||
choices = [1, 2, 3, 4]
|
||
|
||
# 使用select函数进行分类
|
||
zone_classification = pl.select(
|
||
conditions=conditions,
|
||
choices=choices,
|
||
default=0 # 0: 其他情况
|
||
)
|
||
|
||
return stock_df.with_columns(zone_classification.alias('cat_winner_price_zone'))
|
||
|
||
|
||
class FlowChipConsistencyOperator(StockWiseOperator):
|
||
"""主力行为与筹码结构一致性算子"""
|
||
|
||
def __init__(self):
|
||
config = OperatorConfig(
|
||
name="flow_chip_consistency",
|
||
description="主力行为与筹码结构一致性",
|
||
required_columns=['buy_lg_vol', 'buy_elg_vol', 'sell_lg_vol', 'sell_elg_vol',
|
||
'close', 'cost_15pct', 'cost_50pct'],
|
||
output_columns=['flow_chip_consistency'],
|
||
parameters={}
|
||
)
|
||
super().__init__(config)
|
||
|
||
def apply_stock(self, stock_df: pl.DataFrame, **kwargs) -> pl.DataFrame:
|
||
"""计算主力行为与筹码结构一致性"""
|
||
# 计算大单净买入量
|
||
lg_elg_net_buy_vol = (
|
||
pl.col('buy_lg_vol') + pl.col('buy_elg_vol') -
|
||
pl.col('sell_lg_vol') - pl.col('sell_elg_vol')
|
||
)
|
||
|
||
# 判断价格是否接近下方筹码密集区
|
||
price_near_low_support = (
|
||
(pl.col('close') > pl.col('cost_15pct')) &
|
||
(pl.col('close') < pl.col('cost_50pct'))
|
||
)
|
||
|
||
# 计算一致性:主力净买入 * 价格位置指示器
|
||
consistency = lg_elg_net_buy_vol * price_near_low_support.cast(int)
|
||
|
||
return stock_df.with_columns(consistency.alias('flow_chip_consistency'))
|
||
|
||
|
||
class ProfitTakingVsAbsorptionOperator(StockWiseOperator):
|
||
"""获利了结压力/承接盘强度算子"""
|
||
|
||
def __init__(self):
|
||
config = OperatorConfig(
|
||
name="profit_taking_vs_absorb",
|
||
description="获利了结压力vs承接盘强度",
|
||
required_columns=['buy_lg_vol', 'buy_elg_vol', 'sell_lg_vol', 'sell_elg_vol',
|
||
'winner_rate'],
|
||
output_columns=['profit_taking_vs_absorb'],
|
||
parameters={}
|
||
)
|
||
super().__init__(config)
|
||
|
||
def apply_stock(self, stock_df: pl.DataFrame, **kwargs) -> pl.DataFrame:
|
||
"""计算获利了结压力vs承接盘强度"""
|
||
# 计算大单净买入量
|
||
lg_elg_net_buy_vol = (
|
||
pl.col('buy_lg_vol') + pl.col('buy_elg_vol') -
|
||
pl.col('sell_lg_vol') - pl.col('sell_elg_vol')
|
||
)
|
||
|
||
# 判断高获利盘
|
||
high_winner_rate_flag = (pl.col('winner_rate') > 0.7).cast(int)
|
||
|
||
# 计算因子:主力净买入 * 高获利盘指示器
|
||
# 正值表示高获利盘下主力仍在买入(承接),负值表示主力在卖出(了结)
|
||
factor = lg_elg_net_buy_vol * high_winner_rate_flag
|
||
|
||
return stock_df.with_columns(factor.alias('profit_taking_vs_absorb'))
|
||
|
||
|
||
class ChipConcentrationChangeOperator(StockWiseOperator):
|
||
"""筹码集中度变化算子"""
|
||
|
||
def __init__(self, n: int = 20):
|
||
config = OperatorConfig(
|
||
name=f"chip_conc_std_{n}",
|
||
description=f"{n}日筹码集中度变化",
|
||
required_columns=['cost_85pct', 'cost_15pct', 'weight_avg'],
|
||
output_columns=[f'chip_conc_std_{n}'],
|
||
parameters={'n': n}
|
||
)
|
||
super().__init__(config)
|
||
self.n = n
|
||
|
||
def apply_stock(self, stock_df: pl.DataFrame, **kwargs) -> pl.DataFrame:
|
||
"""计算筹码集中度变化"""
|
||
epsilon = 1e-8
|
||
|
||
# 计算成本区间标准化值
|
||
cost_range_norm = (pl.col('cost_85pct') - pl.col('cost_15pct')) / (pl.col('weight_avg') + epsilon)
|
||
|
||
# 计算滚动标准差
|
||
conc_std = cost_range_norm.rolling_std(window=self.n)
|
||
|
||
return stock_df.with_columns(conc_std.alias(f'chip_conc_std_{self.n}'))
|
||
|
||
|
||
class CostBreakoutConfirmationOperator(StockWiseOperator):
|
||
"""成本突破确认算子"""
|
||
|
||
def __init__(self, m: int = 5):
|
||
config = OperatorConfig(
|
||
name=f"cost_break_confirm_cnt_{m}",
|
||
description=f"{m}日成本突破确认",
|
||
required_columns=['close', 'cost_85pct', 'cost_15pct',
|
||
'buy_lg_vol', 'buy_elg_vol', 'sell_lg_vol', 'sell_elg_vol'],
|
||
output_columns=[f'cost_break_confirm_cnt_{m}'],
|
||
parameters={'m': m}
|
||
)
|
||
super().__init__(config)
|
||
self.m = m
|
||
|
||
def apply_stock(self, stock_df: pl.DataFrame, **kwargs) -> pl.DataFrame:
|
||
"""计算成本突破确认"""
|
||
# 获取前一日的成本位
|
||
prev_cost_85 = pl.col('cost_85pct').shift(1)
|
||
prev_cost_15 = pl.col('cost_15pct').shift(1)
|
||
|
||
# 判断突破
|
||
break_up = pl.col('close') > prev_cost_85
|
||
break_down = pl.col('close') < prev_cost_15
|
||
|
||
# 计算大单净流
|
||
net_lg_flow_vol = (
|
||
pl.col('buy_lg_vol') + pl.col('buy_elg_vol') -
|
||
pl.col('sell_lg_vol') - pl.col('sell_elg_vol')
|
||
)
|
||
|
||
# 判断确认信号
|
||
confirm_up = break_up & (net_lg_flow_vol > 0)
|
||
confirm_down = break_down & (net_lg_flow_vol < 0)
|
||
|
||
# 计算净确认信号
|
||
net_confirm = confirm_up.cast(int) - confirm_down.cast(int)
|
||
|
||
# 计算m日累计
|
||
confirm_cnt = net_confirm.rolling_sum(window=self.m)
|
||
|
||
return stock_df.with_columns(confirm_cnt.alias(f'cost_break_confirm_cnt_{self.m}'))
|
||
|
||
|
||
# 筹码分布因子集合
|
||
CHIP_DISTRIBUTION_OPERATORS = [
|
||
ChipConcentrationOperator(),
|
||
ChipSkewnessOperator(),
|
||
FloatingChipProxyOperator(),
|
||
CostSupportChangeOperator(),
|
||
WinnerPriceZoneOperator(),
|
||
FlowChipConsistencyOperator(),
|
||
ProfitTakingVsAbsorptionOperator(),
|
||
ChipConcentrationChangeOperator(),
|
||
CostBreakoutConfirmationOperator(),
|
||
]
|
||
|
||
|
||
def apply_chip_distribution_factors(df: pl.DataFrame, operators: List = None) -> pl.DataFrame:
|
||
"""
|
||
应用所有筹码分布因子
|
||
|
||
Args:
|
||
df: 输入的Polars DataFrame
|
||
operators: 要应用的算子列表,如果为None则使用默认列表
|
||
|
||
Returns:
|
||
添加了筹码分布因子的DataFrame
|
||
"""
|
||
if operators is None:
|
||
operators = CHIP_DISTRIBUTION_OPERATORS
|
||
|
||
result_df = df
|
||
for operator in operators:
|
||
result_df = operator(result_df)
|
||
|
||
return result_df
|