factor优化,改为polars
This commit is contained in:
312
main/factor/polars_chip_factors.py
Normal file
312
main/factor/polars_chip_factors.py
Normal file
@@ -0,0 +1,312 @@
|
||||
"""
|
||||
筹码分布因子 - 使用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
|
||||
Reference in New Issue
Block a user