금융 트레이딩 강화학습을 위한 보상함수 아이디어들

2024. 11. 8. 19:51금융공학/딥러닝

 

 

강화학습을 금융 트레이딩에 적용할 때 포트폴리오 수익률 외에도 다양한 보상 함수 설계가 가능합니다. 잘 설계된 보상 함수는 에이전트가 원하는 행동을 학습하게끔 유도하는 역할을 하며, 특히 수익률뿐만 아니라 리스크 관리안정적인 성과를 동시에 고려하도록 설계할 수 있습니다. 다음은 다양한 보상 함수 설계 방법과 그 계산 사례들입니다.

 

1. 수익률과 최대 하락폭(Drawdown) 고려

  • 목표: 수익률을 최적화하되, 최대 하락폭을 줄이는 방향으로 학습.
  • 설명: 포트폴리오의 최대 하락폭을 줄이는 방향으로 에이전트를 유도하여 리스크 관리도 함께 학습할 수 있습니다.\
def reward_with_drawdown(history):
    current_value = history["portfolio_valuation"][-1]
    prev_value = history["portfolio_valuation"][-2]
    return_ratio = np.log(current_value / prev_value)
    
    max_value = np.max(history["portfolio_valuation"])
    drawdown = (max_value - current_value) / max_value
    
    # 수익률 - 하락폭 페널티 (하락폭이 크면 보상 감소)
    return return_ratio - drawdown

 

2. 변동성 조절 기반 보상

  • 목표: 높은 수익률을 목표로 하되, 변동성을 줄여 안정적인 수익을 추구.
  • 설명: 수익률이 높더라도 변동성이 크면 예측이 어려워지므로, 변동성이 큰 구간에서는 보상을 낮춰 변동성을 억제합니다.
def reward_with_volatility(history):
    current_value = history["portfolio_valuation"][-1]
    prev_value = history["portfolio_valuation"][-2]
    return_ratio = np.log(current_value / prev_value)

    # 최근 N 기간 동안의 변동성 계산
    recent_returns = np.diff(np.log(history["portfolio_valuation"][-20:]))
    volatility = np.std(recent_returns)

    # 수익률 - 변동성 페널티 (변동성이 크면 보상 감소)
    return return_ratio - volatility

 

3. 거래 비용을 고려한 순수익 보상

  • 목표: 실제 수익률에서 거래 비용을 차감하여 과도한 거래를 억제.
  • 설명: 거래가 빈번해질수록 수익이 거래 비용으로 감소하므로, 거래 비용을 고려하여 보상을 계산하면 과도한 거래를 방지할 수 있습니다.
def reward_with_transaction_cost(history, transaction_cost_rate=0.001):
    current_value = history["portfolio_valuation"][-1]
    prev_value = history["portfolio_valuation"][-2]
    return_ratio = np.log(current_value / prev_value)

    # 거래 발생 시 거래 비용 차감
    position_changes = np.sum(np.abs(np.diff(history["position"])))
    transaction_cost = transaction_cost_rate * position_changes
    
    return return_ratio - transaction_cost

 

4. 샤프 비율(Sharpe Ratio) 기반 보상

  • 목표: 위험 대비 수익률을 극대화.
  • 설명: 샤프 비율은 수익률을 변동성으로 나눈 값으로, 위험 대비 수익률을 나타냅니다. 높은 샤프 비율은 안정적인 수익성을 나타내므로, 이를 통해 학습 방향을 설정할 수 있습니다.
def reward_with_sharpe_ratio(history):
    returns = np.diff(np.log(history["portfolio_valuation"]))
    avg_return = np.mean(returns)
    volatility = np.std(returns)

    sharpe_ratio = avg_return / (volatility + 1e-8)  # 분모가 0이 되는 것을 방지
    return sharpe_ratio

 

5. 칼마 비율(Calmar Ratio) 기반 보상

  • 목표: 최대 하락폭 대비 수익률 최적화.
  • 설명: 칼마 비율은 연간 수익률을 최대 하락폭으로 나눈 값으로, 위험 관리가 중요한 환경에서 유리합니다.
def reward_with_calmar_ratio(history):
    returns = np.diff(np.log(history["portfolio_valuation"]))
    avg_return = np.mean(returns)

    max_value = np.max(history["portfolio_valuation"])
    max_drawdown = (max_value - history["portfolio_valuation"][-1]) / max_value

    calmar_ratio = avg_return / (max_drawdown + 1e-8)  # 분모가 0이 되는 것을 방지
    return calmar_ratio

 

6. 포트폴리오 회전율(Turnover)을 고려한 보상

  • 목표: 자산 비율의 잦은 변동을 억제하여 안정적인 트레이딩 유도.
  • 설명: 포트폴리오 회전율이 높으면 과도한 거래가 발생하므로, 이를 줄이기 위해 자산 비율 변화에 페널티를 부여합니다.
def reward_with_turnover_penalty(history, turnover_penalty=0.005):
    current_value = history["portfolio_valuation"][-1]
    prev_value = history["portfolio_valuation"][-2]
    return_ratio = np.log(current_value / prev_value)

    # 포트폴리오 회전율 계산
    turnover = np.sum(np.abs(np.diff(history["position"]))) / len(history["position"])

    # 회전율에 페널티 부여
    return return_ratio - turnover_penalty * turnover

 

7. 정확한 예측력 보상

  • 목표: 시장의 예측에 따라 트레이딩을 수행하도록 유도.
  • 설명: 에이전트가 시장의 방향성을 맞춘 경우에만 보상을 주어 에이전트가 시장 예측 능력을 가지도록 학습합니다.
def reward_based_on_market_prediction(history):
    current_value = history["portfolio_valuation"][-1]
    prev_value = history["portfolio_valuation"][-2]
    return_ratio = np.log(current_value / prev_value)

    # 시장 방향성과 트레이딩 방향성이 일치할 때 보상
    market_direction = np.sign(history["market_price"][-1] - history["market_price"][-2])
    trade_direction = np.sign(history["position"][-1])
    
    prediction_reward = return_ratio if market_direction == trade_direction else -abs(return_ratio)
    return prediction_reward

 

 

8. 포트폴리오 위험 허용 한도 내에서 수익 극대화

  • 목표: 특정 위험 한도 내에서 수익을 최적화.
  • 설명: 위험을 초과하면 페널티를 부여하여 위험 한도를 유지하면서 수익을 극대화하도록 유도합니다.
def reward_with_risk_threshold(history, risk_threshold=0.02):
    current_value = history["portfolio_valuation"][-1]
    prev_value = history["portfolio_valuation"][-2]
    return_ratio = np.log(current_value / prev_value)

    # 특정 위험 허용 한도 초과 시 페널티
    risk = np.std(np.diff(np.log(history["portfolio_valuation"][-20:])))
    penalty = max(0, risk - risk_threshold)
    
    return return_ratio - penalty

 

9. 통합

다양한 요소를 함께 고려하여 수익률, 리스크, 안정성을 조화롭게 최적화하는 보상 함수를 만들어 보겠습니다. 이 보상 함수는 다음과 같은 요소들을 조합하여 구성됩니다:

  1. 수익률: 전체적인 수익률을 고려하되, 다른 요소들과의 균형을 유지하도록 설정합니다.
  2. 최대 하락폭(Drawdown): 포트폴리오가 큰 손실을 입지 않도록 최대 하락폭에 페널티를 부여합니다.
  3. 변동성: 변동성이 큰 트레이딩은 위험하므로 변동성을 고려해 안정적인 성과를 유도합니다.
  4. 거래 비용: 과도한 거래를 억제하여 거래 비용을 절감합니다.
  5. 샤프 비율: 변동성 대비 수익률을 측정하여 리스크 대비 수익이 높아지도록 유도합니다.
  6. 포트폴리오 회전율: 잦은 포트폴리오 변경을 방지합니다.
def balanced_reward_function(history, transaction_cost_rate=0.001, turnover_penalty=0.005, risk_threshold=0.02):
    """
    다양한 리스크 관리와 수익 요소를 고려한 종합적인 보상 함수.
    
    Parameters:
    - history: 트레이딩 환경에서 제공되는 포트폴리오 및 시장 정보 기록.
    - transaction_cost_rate: 거래 발생 시 수익에서 차감할 거래 비용 비율.
    - turnover_penalty: 포트폴리오 회전율에 부과할 페널티 비율.
    - risk_threshold: 허용할 수 있는 최대 리스크 (변동성 기준).

    Returns:
    - 종합 보상 점수 (float)
    """
    # 수익률 계산 (log 수익률)
    current_value = history["portfolio_valuation"][-1]
    prev_value = history["portfolio_valuation"][-2]
    return_ratio = np.log(current_value / prev_value)

    # 최대 하락폭 계산
    max_value = np.max(history["portfolio_valuation"])
    drawdown = (max_value - current_value) / max_value

    # 최근 N 기간 동안의 변동성 계산
    recent_returns = np.diff(np.log(history["portfolio_valuation"][-20:]))
    volatility = np.std(recent_returns)

    # 거래 비용 계산
    position_changes = np.sum(np.abs(np.diff(history["position"])))
    transaction_cost = transaction_cost_rate * position_changes

    # 샤프 비율 계산
    avg_return = np.mean(recent_returns)
    sharpe_ratio = avg_return / (volatility + 1e-8)  # 분모가 0이 되는 것을 방지
    
    # 포트폴리오 회전율에 대한 페널티 계산
    turnover = np.sum(np.abs(np.diff(history["position"]))) / len(history["position"])

    # 리스크 초과 여부를 확인하고 페널티 추가
    risk_penalty = max(0, volatility - risk_threshold)

    # 보상 계산: 수익률, 샤프 비율을 더한 후 거래 비용, 변동성, 최대 하락폭 페널티 차감
    reward = (
        return_ratio                 # 수익률 보상
        + 0.5 * sharpe_ratio         # 샤프 비율 보상 (가중치 0.5)
        - 0.5 * drawdown             # 최대 하락폭 페널티 (가중치 0.5)
        - 0.5 * volatility           # 변동성 페널티 (가중치 0.5)
        - transaction_cost           # 거래 비용 페널티
        - turnover_penalty * turnover # 포트폴리오 회전율 페널티
        - risk_penalty               # 리스크 초과 페널티
    )

    return reward