[베이지안 with Python] 'Financial prediction'

 

Financial prediction

제곱오차손실 함수가 항상 최고? (다양한 형태의 손실함수)

$\ $미래 실제 주식 수익률이 1% 정도로 매우 작다고 가정해보자. 주식 수익률 예측 모델에서는 기존의 제곱오차손실 방법을 사용하기에는 뚜렷한 한계점이 있다. 예를 들어 모델의 예측을 통해 우리가 3%의 수익을 얻었을 때와, 모델의 예측을 통해 1%의 손실을 봤을 때, 제곱오차손실 방법론은 이를 같은 loss로 취급한다.

$$ (0.01 - (-0.01))^2 = (0.01 - 0.03)^2 = 0.004 $$

$\ $즉, 방향의 개념 또는 양수, 음수의 개념을 포함할 수 없다는 것이 문제가 된다. 다음의 그래프를 보면서 조금 더 자세히 살펴보자.

figsize(12.5, 4)


def stock_loss(true_return, yhat, alpha = 100.):
    if true_return * yhat < 0:
        #opposite signs, not good
        return alpha*yhat**2 - np.sign(true_return)*yhat \
                        + abs(true_return)
    else:
        return abs(true_return - yhat)


true_value = .05
pred = np.linspace(-.04, .12, 75)

plt.plot(pred, [stock_loss(true_value, _p) for _p in pred], \
        label = "Loss associated with\n prediction if true value = 0.05", lw =3)
plt.vlines(0, 0, .25, linestyles="--")

plt.xlabel("prediction")
plt.ylabel("loss")
plt.xlim(-0.04, .12)
plt.ylim(0, 0.25)

true_value = -.02
plt.plot(pred, [stock_loss(true_value, _p) for _p in pred], alpha = 0.6, \
        label = "Loss associated with\n prediction if true value = -0.02", lw =3)
plt.legend()
plt.title("Stock returns loss if true value = 0.05, -0.02");

$\ $plot생성 파이썬 코드에서도 확인 할 수 있고, plot에서 직접적으로 보여지지만, 해당 plot은 다음과 같은 크게 세개의 특징을 보여주고 있다.

  1. 실제 주식수익률(참값)과, 모델이 제시한 수익률(모델값)이 같은 경우에 loss는 0이다.
  2. 참값과 모델값의 부호가 같은 경우에, 손실은 참값과 모델값의 차이 값에 비례해 선형적으로 증가한다.
  3. 참값과 모델값의 부호가 다른 경우에, 손실은 참값과 모델값의 차이 값에 비례해 비선형적(제곱)으로 증가한다.

1번은 너무나도 당연한 이야기이고, 2번과 3번에 대해 이야기를 나누기 전에 우리가 먼저 이해하고 넘어가야 할 것이 있다. 2, 3번에 따르면 이 상황에서 손실은 무조건적으로 늘어난다는 것인데, 실제 주식수익률에 비해 모델이 제시한 수익률이 높으면 해당 모델은 무조건적으로 훌륭한 모델이지 않은가? 왜 손실이 더 늘어나지?

모델이 돈을 더 많이 줄 기회를 준건데 왜 손실함수는 손실에 계속 늘어난다고 말할까

금융에서는 수익률을 높이는 게 무조건적으로 좋은 상황이 아니라, 하방 수익률을 예측해야 하는 경우도 있다. 즉, 실제 수익률에 대하여 정확한 값을 예측하는 경우가 아니라면, 손실로 볼 수 밖에 없다.
이제, 2, 3번의 증가 추이에 관한 이야기를 더 해보자. 해당 그래프를 잘 보면, 예측이 0인 지점을 기준으로 선형적 추이와 비선형적 추이가 변하는 것을 볼 수 있는데, 이는 우리가 수익률의 부호를 맞추지 못하면 어마어마하게 손실이 증가한다는 것을 반영한다.

그래서 항상 최소제곱손실을 손실함수로 쓸수는 없다! 다른 것도 고려해야 돼! 라고 저자는 외치는 건가

trading signal에 대한 회귀분석

미래 수익률을 아주 잘 예측하는 모델이 주어졌을 때, 해당 모델이 출력하는 trading signal에 대해 회귀분석을 해보자. 현재 주어진 데이터셋은 인위적인 것이다.

## Code to create artificial data
N = 100
X = 0.025*np.random.randn(N)
Y = 0.5*X + 0.01*np.random.randn(N)

ls_coef_ = np.cov(X, Y)[0,1]/np.var(X)
ls_intercept = Y.mean() - ls_coef_*X.mean()

plt.scatter(X, Y, c="k")
plt.xlabel("trading signal")
plt.ylabel("returns")
plt.title("Empirical returns vs trading signal")
plt.plot(X, ls_coef_*X + ls_intercept, label = "Least-squares line")
plt.xlim(X.min(), X.max())
plt.ylim(Y.min(), Y.max())
plt.legend(loc="upper left");

$\ $모델이 출력하는 trading signal과 실제 수익률 간의 관계를 다음과 같이 표현하자.

$$ R = \alpha + \beta x + \epsilon$$

여기에서 \(\alpha, \beta\)는 아직 알려지지 않은 값이며, \(\epsilon \thicksim Normal(0,\sigma)\)가 성립한다. \(\alpha, \beta\) 에 대한 가장 흔한 확률분포는 Normal 사전분포이다. 이에 대한 사후확률분포 추론을 진행하자.

import pymc3 as pm

with pm.Model() as model:
    std = pm.Uniform("std", 0, 100)

    beta = pm.Normal("beta", mu=0, sd=100)
    alpha = pm.Normal("alpha", mu=0, sd=100)

    mean = pm.Deterministic("mean", alpha + beta*X)

    obs = pm.Normal("obs", mu=mean, sd=std, observed=Y)

    trace = pm.sample(100000, step=pm.Metropolis())
    burned_trace = trace[20000:]