feat: Initialize PolyWeather project structure including modules for data collection, analysis, strategy, trading, utilities, configuration, and a Streamlit dashboard.
This commit is contained in:
@@ -0,0 +1,153 @@
|
||||
from loguru import logger
|
||||
|
||||
class PositionManager:
|
||||
"""
|
||||
仓位管理 - Kelly公式动态仓位计算
|
||||
"""
|
||||
|
||||
def __init__(self, config=None):
|
||||
self.config = config or {}
|
||||
self.max_position_ratio = self.config.get("max_position_ratio", 0.25) # 最大单笔25%
|
||||
self.max_total_exposure = self.config.get("max_total_exposure", 0.80) # 最大总仓位80%
|
||||
self.min_trade_size = self.config.get("min_trade_size", 10) # 最小交易额$10
|
||||
logger.info("Initializing Position Manager...")
|
||||
|
||||
def kelly_criterion(self, win_prob: float, odds: float) -> float:
|
||||
"""
|
||||
Kelly公式计算最优投资比例
|
||||
|
||||
f = (bp - q) / b
|
||||
f: 应投资的资金比例
|
||||
b: 赔率 (盈利/亏损)
|
||||
p: 胜率
|
||||
q: 败率 (1-p)
|
||||
|
||||
Args:
|
||||
win_prob: 预测胜率 (0-1)
|
||||
odds: 赔率
|
||||
|
||||
Returns:
|
||||
float: 建议投资比例 (0-1)
|
||||
"""
|
||||
if win_prob <= 0 or win_prob >= 1 or odds <= 0:
|
||||
return 0.0
|
||||
|
||||
q = 1 - win_prob
|
||||
f = (win_prob * odds - q) / odds
|
||||
|
||||
# 限制最大仓位
|
||||
f = max(0, min(f, self.max_position_ratio))
|
||||
|
||||
logger.debug(f"Kelly ratio: {f:.4f} (win_prob={win_prob:.2f}, odds={odds:.2f})")
|
||||
return f
|
||||
|
||||
def calculate_position_size(self,
|
||||
total_capital: float,
|
||||
win_prob: float,
|
||||
market_price: float,
|
||||
current_exposure: float = 0) -> dict:
|
||||
"""
|
||||
计算建议仓位大小
|
||||
|
||||
Args:
|
||||
total_capital: 总资金
|
||||
win_prob: 模型预测胜率
|
||||
market_price: 当前市场价格 (0-1)
|
||||
current_exposure: 当前已有仓位占比
|
||||
|
||||
Returns:
|
||||
dict: 包含建议仓位大小和相关信息
|
||||
"""
|
||||
# 计算赔率
|
||||
if market_price <= 0 or market_price >= 1:
|
||||
return {"size": 0, "error": "Invalid market price"}
|
||||
|
||||
odds = (1 - market_price) / market_price
|
||||
|
||||
# Kelly计算
|
||||
kelly_ratio = self.kelly_criterion(win_prob, odds)
|
||||
|
||||
# 检查总仓位限制
|
||||
available_ratio = self.max_total_exposure - current_exposure
|
||||
if available_ratio <= 0:
|
||||
return {
|
||||
"size": 0,
|
||||
"kelly_ratio": kelly_ratio,
|
||||
"reason": "Max exposure reached"
|
||||
}
|
||||
|
||||
# 实际使用比例
|
||||
actual_ratio = min(kelly_ratio, available_ratio)
|
||||
|
||||
# 计算金额
|
||||
position_size = total_capital * actual_ratio
|
||||
|
||||
# 检查最小交易额
|
||||
if position_size < self.min_trade_size:
|
||||
return {
|
||||
"size": 0,
|
||||
"kelly_ratio": kelly_ratio,
|
||||
"reason": f"Below minimum trade size (${self.min_trade_size})"
|
||||
}
|
||||
|
||||
return {
|
||||
"size": position_size,
|
||||
"kelly_ratio": kelly_ratio,
|
||||
"actual_ratio": actual_ratio,
|
||||
"odds": odds,
|
||||
"expected_return": (win_prob * odds - (1 - win_prob)) * position_size
|
||||
}
|
||||
|
||||
def should_exit(self,
|
||||
entry_price: float,
|
||||
current_price: float,
|
||||
current_prediction: float,
|
||||
stop_loss: float = 0.15,
|
||||
take_profit: float = 0.30) -> dict:
|
||||
"""
|
||||
判断是否应该平仓
|
||||
|
||||
Args:
|
||||
entry_price: 入场价格
|
||||
current_price: 当前价格
|
||||
current_prediction: 当前模型预测
|
||||
stop_loss: 止损比例
|
||||
take_profit: 止盈比例
|
||||
|
||||
Returns:
|
||||
dict: 退出建议
|
||||
"""
|
||||
if entry_price <= 0:
|
||||
return {"should_exit": False}
|
||||
|
||||
pnl_ratio = (current_price - entry_price) / entry_price
|
||||
|
||||
# 止损
|
||||
if pnl_ratio < -stop_loss:
|
||||
return {
|
||||
"should_exit": True,
|
||||
"reason": "STOP_LOSS",
|
||||
"pnl_ratio": pnl_ratio
|
||||
}
|
||||
|
||||
# 止盈
|
||||
if pnl_ratio > take_profit:
|
||||
return {
|
||||
"should_exit": True,
|
||||
"reason": "TAKE_PROFIT",
|
||||
"pnl_ratio": pnl_ratio
|
||||
}
|
||||
|
||||
# 模型预测反转
|
||||
if current_prediction < 0.4: # 预测胜率下降
|
||||
return {
|
||||
"should_exit": True,
|
||||
"reason": "PREDICTION_REVERSAL",
|
||||
"pnl_ratio": pnl_ratio,
|
||||
"current_prediction": current_prediction
|
||||
}
|
||||
|
||||
return {
|
||||
"should_exit": False,
|
||||
"pnl_ratio": pnl_ratio
|
||||
}
|
||||
Reference in New Issue
Block a user