mirror of
https://github.com/microsoft/qlib.git
synced 2026-11-12 05:50:57 +08:00
* Update test_qlib_from_source.yml * add ipynb format check to workflow * test ipynb CI * modify nbqa check path * add pylint flake8 mypy check to ipynb * check ipynb with black and pylint * reformat .ipynb files * format line length nbqa black . -l 120 * update nbqa .ipynb format CI * format old ipynb files * add nbconvert check to CI * adjust CI order to avoid repeating download data
68 KiB
68 KiB
In [ ]:
from collections import namedtuple
from typing import Any
from qlib.rl.simulator import Simulator
State = namedtuple("State", ["value", "last_action"])
class SimpleSimulator(Simulator[float, State, float]):
def __init__(self, initial: float, nsteps: int, **kwargs: Any) -> None:
super().__init__(initial)
self.value = initial
self.last_action = 0.0
self.remain_steps = nsteps
def step(self, action: float) -> None:
assert 0.0 <= action <= self.value
self.last_action = action
self.remain_steps -= 1
def get_state(self) -> State:
return State(self.value, self.last_action)
def done(self) -> bool:
return self.remain_steps == 0In [ ]:
from typing import Tuple
import numpy as np
from gym import spaces
from qlib.rl.interpreter import StateInterpreter
class SimpleStateInterpreter(StateInterpreter[Tuple[float, float], np.ndarray]):
def interpret(self, state: State) -> np.ndarray:
# Convert state.value to a 1D Numpy array
# last_action is not used by agents.
return np.array([state.value], dtype=np.float32)
@property
def observation_space(self) -> spaces.Box:
return spaces.Box(0, np.inf, shape=(1,), dtype=np.float32)
state_interpreter = SimpleStateInterpreter()In [ ]:
from qlib.rl.interpreter import ActionInterpreter
class SimpleActionInterpreter(ActionInterpreter[State, int, float]):
def __init__(self, n_value: int) -> None:
self.n_value = n_value
@property
def action_space(self) -> spaces.Discrete:
return spaces.Discrete(self.n_value + 1)
def interpret(self, simulator_state: State, action: int) -> float:
assert 0 <= action <= self.n_value
# simulator_state.value is used as the denominator
return simulator_state.value * (action / self.n_value)
action_interpreter = SimpleActionInterpreter(n_value=10)In [ ]:
from qlib.rl.reward import Reward
class SimpleReward(Reward[State]):
def reward(self, simulator_state: State) -> float:
# Use last_action to calculate reward. This is why it should be in the state.
rew = simulator_state.last_action / simulator_state.value
return rew
reward = SimpleReward()In [ ]:
from typing import List
import torch
from torch import nn
from qlib.rl.order_execution import PPO
class SimpleFullyConnect(nn.Module):
def __init__(self, dims: List[int]) -> None:
super().__init__()
self.dims = [1] + dims
self.output_dim = dims[-1]
layers = []
for in_dim, out_dim in zip(self.dims[:-1], self.dims[1:]):
layers.append(nn.Linear(in_dim, out_dim))
layers.append(nn.ReLU())
self.fc = nn.Sequential(*layers)
def forward(self, x: torch.Tensor) -> torch.Tensor:
return self.fc(x)
policy = PPO(
network=SimpleFullyConnect(dims=[16, 8]),
obs_space=state_interpreter.observation_space,
action_space=action_interpreter.action_space,
lr=0.01,
)In [ ]:
from torch.utils.data import Dataset
class SimpleDataset(Dataset):
def __init__(self, positions: List[float]) -> None:
self.positions = positions
def __len__(self) -> int:
return len(self.positions)
def __getitem__(self, index: int) -> float:
return self.positions[index]
dataset = SimpleDataset(positions=[10.0, 50.0, 100.0])In [ ]:
from pathlib import Path
from typing import cast
from qlib.rl.trainer import Checkpoint, train
NSTEPS = 10
trainer_kwargs = {
"max_iters": 10,
"finite_env_type": "dummy",
"callbacks": [
Checkpoint(
dirpath=Path("./checkpoints"),
every_n_iters=1,
save_latest="copy",
)
],
}
vessel_kwargs = {
"update_kwargs": {"batch_size": 16, "repeat": 5},
"episode_per_iter": 50,
}
print("Training started")
train(
simulator_fn=lambda position: SimpleSimulator(position, NSTEPS),
state_interpreter=state_interpreter,
action_interpreter=action_interpreter,
policy=policy,
reward=reward,
initial_states=cast(List[float], SimpleDataset([10.0, 50.0, 100.0])),
trainer_kwargs=trainer_kwargs,
vessel_kwargs=vessel_kwargs,
)
print("Training finished")In [ ]:
from tianshou.data import Batch
simulator = SimpleSimulator(100.0, NSTEPS)
state = simulator.get_state()
obs = [{"obs": state_interpreter.interpret(state)}]
policy_out = policy(Batch(obs))
act = float(action_interpreter.interpret(state, policy_out.act))
simulator.step(act)
rew = float(reward(simulator.get_state()))
print(f"Action = {act:.6f}, Reward = {rew:.6f}.")