相对于全仓买入, 增加仓位管理(凯利公式), 在交易过程中动态更新胜率和赔率, 有效降低风险回撤和资金回测.
def simulate_kelly_trading(stock_data, signal, initial_balance=100000, commission_rate=0.0005, slippage_rate=0.01, tax_rate=0.001):
balance = initial_balance
position = 0
trade_history = []
portfolio_value_history = []
peak_value = initial_balance
max_risk_drawdown = 0
max_capital_drawdown = 0
win_count = 0
loss_count = 0
total_win = 0
total_loss = 0
stock_data['trade_date'] = pd.to_datetime(stock_data['trade_date'], format='%Y%m%d')
for index, row in stock_data.iterrows():
if signal[index] == 'buy' and position == 0:
if win_count + loss_count > 0:
win_rate = win_count / (win_count + loss_count)
avg_win = total_win / win_count if win_count > 0 else 0
avg_loss = total_loss / loss_count if loss_count > 0 else 0
kelly_fraction = calculate_kelly_position(win_rate, avg_win, avg_loss)
else:
kelly_fraction = 0.2
position = int((balance * kelly_fraction) / (row['close'] + slippage_rate))
position = int(position / 100) * 100
buy_cash = (row['close'] + slippage_rate) * position
commission = round(max(buy_cash * commission_rate, 5), 2)
balance = balance - buy_cash - commission
trade_history.append(('buy', stock_data['trade_date'][index], row['close']))
elif signal[index] =='sell' and position > 0:
last_balance = balance
sell_cash = (row['close'] - slippage_rate) * position
commission = round(max(sell_cash * commission_rate, 5), 2)
tax = round(sell_cash * tax_rate, 2)
balance = balance + sell_cash - commission - tax
trade_history.append(('sell', stock_data['trade_date'][index], row['close']))
position = 0
if balance > last_balance:
win_count += 1
total_win += balance - last_balance
else:
loss_count += 1
total_loss += last_balance - balance
portfolio_value = balance + position * row['close']
portfolio_value_history.append(portfolio_value)
if portfolio_value > peak_value:
peak_value = portfolio_value
risk_drawdown = (peak_value - portfolio_value) / peak_value
if risk_drawdown > max_risk_drawdown:
max_risk_drawdown = risk_drawdown
trade_history.append(('max_risk_drawdown', stock_data['trade_date'][index], max_risk_drawdown))
capital_drawdown = (initial_balance - portfolio_value) / initial_balance
if capital_drawdown > max_capital_drawdown:
max_capital_drawdown = capital_drawdown
trade_history.append(('max_capital_drawdown', stock_data['trade_date'][index], max_capital_drawdown))
if position > 0:
balance = position * stock_data.iloc[-1]['close']
trade_history.append(('sell', stock_data.iloc[-1]['trade_date'], stock_data.iloc[-1]['close']))
return balance, trade_history, max_risk_drawdown, max_capital_drawdown
Initl Balance: 100000
Final Balance: 104072.14
Max Risk Drawdown: 18.69%
Max Capital Drawdown: 0.61%