試して学ぶ
教師あり学習では、どの例にも正解が付いています。トレーディングはそうではありません。最適なポジションを教えてくれる人はいません。行動すると、市場が利益か損失で応えます。強化学習はこれを、状態を観測し、行動を取り、報酬を受け取り、新しい状態に移るエージェントとしてモデル化し、時間を通じた報酬の合計を最大化することを目指します。トレーディングでは、状態は直近のリターンや現在のポジション、行動は買い・保有・売り、報酬はそのステップの利益からコストを引いたものです。難しいのは、行動の結果が後で現れ、エージェントが試行によって何が報われるかを見つけなければならない点です。
# Reward of one step: profit from the position held, minus the cost of changing position
def step_reward(position, price_change, previous_position, cost):
return position * price_change - cost * abs(position - previous_position)
print(round(step_reward(1, 0.5, 0, 0.1), 4)) # 0.4 went long, the price rose 0.5, paid 0.1 to trade
print(round(step_reward(-1, 0.5, 1, 0.1), 4)) # -0.7 flipped from long to short just before a rise: lost 0.5 and paid 0.2
print(step_reward(1, 0.5, 1, 0.1)) # 0.5 holding the same position costs nothingQ学習:ある状態での行動の価値
Q学習は表 Q[状態, 行動] を持ちます。その状態でその行動を取り、その後うまく行動した場合に期待される報酬の合計です。各ステップの後、その要素をより良い推定値であるターゲットに近づけます。ターゲットは、いま得た報酬に、次の状態での最良の行動の割引価値を足したもの reward + gamma * max(Q[次の状態]) です。更新は学習率 alpha を使って Q[s, a] += alpha * (ターゲット - Q[s, a]) です。割引率 gamma(0から1)は将来の報酬の重みを表します。gamma = 0 は近視眼的なエージェント、1に近いと辛抱強いエージェントで、系列のリターンは r0 + gamma r1 + gamma^2 r2 + ... です。終端のステップでは次の状態がなく、ターゲットは報酬だけです。
# One Q-learning update on a table of 2 states x 3 actions (short, flat, long)
import numpy as np
def q_update(q, state, action, reward, next_state, alpha, gamma):
updated = q.copy()
target = reward if next_state is None else reward + gamma * updated[next_state].max()
updated[state, action] += alpha * (target - updated[state, action])
return updated
q = np.zeros((2, 3))
q = q_update(q, 0, 2, 1.0, 1, 0.5, 0.9) # in state 0 we went long and earned 1.0
print(q[0]) # [0. 0. 0.5] moved halfway (alpha 0.5) toward the target of 1.0
q = q_update(q, 0, 2, 1.0, 1, 0.5, 0.9)
print(q[0]) # [0. 0. 0.75] a second visit moves it further探索と、動く学習ループの例
常に自分が知っている最良の行動だけを取るエージェントは、別の行動のほうが良いかどうかを知ることができません。イプシロン貪欲法がこれを解決します。確率 epsilon でランダムな行動を探索し、それ以外は Q が最大の行動を活用します(同点なら最初のもの)。epsilon は通常、高く始めて徐々に下げます。ループは、状態を観測し、行動を選び、報酬と次の状態を受け取り、Q を更新し、繰り返す、というものです。上昇日の翌日も上昇しやすいおもちゃの市場では、「昨日は上昇」という状態を見たエージェントが、ロングを保つと報われると学びます。2つの状態と3つの行動の表で十分に示せます。
# A toy market where an up day tends to be followed by another up day; the agent learns to follow the trend
import random
import numpy as np
rng = random.Random(1)
positions = [-1, 0, 1] # action 0 = short, 1 = flat, 2 = long
q = np.zeros((2, 3)) # state 0 = yesterday down, state 1 = yesterday up
alpha, gamma, cost = 0.1, 0.9, 0.0005
state, previous = 1, 0
for step in range(20000):
epsilon = max(0.05, 1 - step / 10000)
u, explore = rng.random(), rng.randrange(3)
action = explore if u < epsilon else int(np.argmax(q[state]))
up = rng.random() < (0.65 if state == 1 else 0.35) # the trend continues 65% of the time
change = 0.01 if up else -0.01
reward = positions[action] * change - cost * abs(positions[action] - previous)
next_state = 1 if up else 0
target = reward + gamma * q[next_state].max()
q[state, action] += alpha * (target - q[state, action])
state, previous = next_state, positions[action]
print(int(np.argmax(q[0])), int(np.argmax(q[1]))) # 0 2 after a down day go short, after an up day go long# The discounted return: with gamma below 1 a reward now is worth more than the same reward later
def discounted_return(rewards, gamma):
total = 0.0
for reward in reversed(rewards):
total = reward + gamma * total
return total
rewards = [1.0, 1.0, 1.0]
print(discounted_return(rewards, 0.5)) # 1.75 1 + 0.5 + 0.25
print(discounted_return(rewards, 1.0)) # 3.0 a patient agent: a plain sum
print(discounted_return(rewards, 0.0)) # 1.0 a short-sighted agent: only the first reward counts- エージェントは状態を観測し、行動し、報酬(利益−コスト)を受け取り、どの行動が報われるかを学ぶ。リターンは割引和
r0 + gamma r1 + gamma^2 r2 + ... - Q学習は
Q[s, a] += alpha * (reward + gamma * max Q[s'] - Q[s, a])(終端ステップではrewardのみ)で更新する。ここでは古い表をその場で書き換えない - イプシロン貪欲法は確率 epsilon で探索し、それ以外は最大の Q を活用する。学習とテストは別の期間で行い、現実的なコストを課し、単純なベースラインと比べる
次は最終プロジェクトです。すべてをまとめた、エンドツーエンドの価格評価または戦略ライブラリを作ります。
ラボ:採点される内容
choose_actionで探索か活用かを選ぶ25点q_updateで1ステップから学習する25点step_rewardで取引にコストを課す25点discounted_returnで将来を足し合わせる25点