Path: blob/master/finrl/agents/portfolio_optimization/utils.py
732 views
from __future__ import annotations12from collections import deque3from random import randint4from random import random56import numpy as np7from torch.utils.data.dataset import IterableDataset8910class PVM:11def __init__(self, capacity, portfolio_size):12"""Initializes portfolio vector memory.1314Args:15capacity: Max capacity of memory.16portfolio_size: Portfolio size.17"""18# initially, memory will have the same actions19self.capacity = capacity20self.portfolio_size = portfolio_size21self.reset()2223def reset(self):24self.memory = [np.array([1] + [0] * self.portfolio_size, dtype=np.float32)] * (25self.capacity + 126)27self.index = 0 # initial index to retrieve data2829def retrieve(self):30last_action = self.memory[self.index]31self.index = 0 if self.index == self.capacity else self.index + 132return last_action3334def add(self, action):35self.memory[self.index] = action363738class ReplayBuffer:39def __init__(self, capacity):40"""Initializes replay buffer.4142Args:43capacity: Max capacity of buffer.44"""45self.buffer = deque(maxlen=capacity)4647def __len__(self):48"""Represents the size of the buffer4950Returns:51Size of the buffer.52"""53return len(self.buffer)5455def append(self, experience):56"""Append experience to buffer. When buffer is full, it pops57an old experience.5859Args:60experience: experience to be saved.61"""62self.buffer.append(experience)6364def sample(self):65"""Sample from replay buffer. All data from replay buffer is66returned and the buffer is cleared.6768Returns:69Sample of batch_size size.70"""71buffer = list(self.buffer)72self.buffer.clear()73return buffer747576class RLDataset(IterableDataset):77def __init__(self, buffer):78"""Initializes reinforcement learning dataset.7980Args:81buffer: replay buffer to become iterable dataset.8283Note:84It's a subclass of pytorch's IterableDataset,85check https://pytorch.org/docs/stable/data.html#torch.utils.data.IterableDataset86"""87self.buffer = buffer8889def __iter__(self):90"""Iterates over RLDataset.9192Returns:93Every experience of a sample from replay buffer.94"""95yield from self.buffer.sample()969798def apply_portfolio_noise(portfolio, epsilon=0.0):99"""Apply noise to portfolio distribution considering its constrains.100101Arg:102portfolio: initial portfolio distribution.103epsilon: maximum rebalancing.104105Returns:106New portolio distribution with noise applied.107"""108portfolio_size = portfolio.shape[0]109new_portfolio = portfolio.copy()110for i in range(portfolio_size):111target_index = randint(0, portfolio_size - 1)112difference = epsilon * random()113# check constrains114max_diff = min(new_portfolio[i], 1 - new_portfolio[target_index])115difference = min(difference, max_diff)116# apply difference117new_portfolio[i] -= difference118new_portfolio[target_index] += difference119return new_portfolio120121122