turns-00055.parquet:19856
dd06f89dc80a8c273fc347e1
turn 30/34gpt-4o-2024-11-20RussianRussia799 words
degenerate_repetitionAbsentFinal dense release
USER
давай ещё раз полный код среды, которая у нас получилась
ASSISTANT
Вот полный обновлённый код среды `StockTradingEnv` с учётом всех ваших изменений:
---
### **Финальная версия `StockTradingEnv`**
```python
import gymnasium as gym
import numpy as np
from gymnasium import spaces
class StockTradingEnv(gym.Env):
"""Среда для RL-торговли акциями."""
def __init__(self, data, initial_balance=1000, window_size=10, max_shares=1):
"""
Args:
data (DataFrame): Рыночные данные с колонками ['Open', 'High', 'Low', 'Close'].
initial_balance (float): Начальный баланс агента.
window_size (int): Размер скользящего окна для наблюдений.
max_shares (int): Максимальное количество акций, которые агент может купить и держать одновременно.
"""
super(StockTradingEnv, self).__init__()
# Лимит на количество акций
self.max_shares = max_shares
# Рыночные данные
assert "Close" in data.columns, "Данные должны содержать колонку 'Close'!"
self.data = data.reset_index(drop=True) # Сбрасываем индексы для удобства доступа
self.n_steps = len(self.data)
# Текущий индекс шага
self.current_step = 0
self.window_size = window_size
# Финансовые метрики
self.initial_balance = initial_balance
self.balance = initial_balance
self.shares = 0
self.net_worth = initial_balance # Чистая стоимость портфеля
# Action Space: 0 = Hold, 1 = Buy, 2 = Sell
self.action_space = spaces.Discrete(3)
# Observation Space: рыночные данные + портфель (6 признаков на каждую свечу)
self.observation_space = spaces.Box(
low=-np.inf, high=np.inf, shape=(window_size, 6), dtype=np.float32
)
def reset(self):
"""Сброс среды в начальное состояние."""
self.current_step = self.window_size # Начинаем с шага после окна
self.balance = self.initial_balance
self.shares = 0
self.net_worth = self.initial_balance
return self._next_observation()
def _next_observation(self):
"""Генерация текущего наблюдения (история + портфель)."""
end = self.current_step
start = max(0, end - self.window_size)
# Рыночные данные (скользящее окно)
market_data = self.data.iloc[start:end][['Open', 'High', 'Low', 'Close']].to_numpy()
# Финансовые показатели (копируем для каждой строки окна)
portfolio = np.array([self.balance, self.net_worth] * self.window_size).reshape(self.window_size, 2)
# Объединяем рыночные данные и портфель
observation = np.hstack([market_data, portfolio])
return observation
def step(self, action):
"""Выполнение действия и переход среды на следующий шаг."""
self.current_step += 1
# Текущая и предыдущая цены закрытия
current_price = self.data.iloc[self.current_step]["Close"]
previous_price = self.data.iloc[self.current_step - 1]["Close"]
# Инициализация наград
reward = 1 # Нейтральная награда
price_reward = 1
trade_reward = 1
# Обработка действий агента
if action == 1: # Buy
if self.balance >= current_price and self.shares < self.max_shares: # Учитываем лимит акций
self.balance -= current_price
self.shares += 1
elif action == 2: # Sell
if self.shares > 0: # Если есть акции для продажи
total_sold_value = self.shares * current_price
self.balance += total_sold_value
self.shares = 0
# Награда за завершение сделки
trade_reward = self.balance / self.initial_balance
reward *= trade_reward
# Обновляем чистую стоимость портфеля
self.net_worth = self.balance + (self.shares * current_price)
# Награда за изменение цены акций (стимул учитывать тренд)
if self.shares > 0: # Если удерживаются акции
price_reward = current_price / previous_price # Если цена растёт, reward > 1
reward *= price_reward
# Проверка завершения эпизода
done = self.current_step >= self.n_steps - 1
# Дополнительная информация для анализа (info)
info = {
"step": self.current_step, # Текущий шаг
"action": action, # Действие агента
"current_price": current_price, # Текущая цена закрытия
"previous_price": previous_price, # Предыдущая цена закрытия
"price_reward": price_reward, # Награда за изменение цены
"trade_reward": trade_reward, # Награда за завершение сделки
"total_reward": reward, # Итоговая награда
"balance": self.balance, # Доступные деньги
"shares": self.shares, # Количество акций
"net_worth": self.net_worth, # Чистая стоимость портфеля
}
return self._next_observation(), reward, done, info
def render(self):
"""Вывод текущего состояния для отладки/визуализации."""
print(f"Step: {self.current_step}, Balance: {self.balance:.2f}, Shares: {self.shares}, Net Worth: {self.net_worth:.2f}")
```
---
### **Что нового в этом коде:**
1. **Ограничение на покупки (`max_shares`):**
- Теперь агент не может купить более `max_shares` акций. Вы задаёте это значение параметром при создании среды (по умолчанию `max_shares=1`).
2. **Расчёт `reward`:**
- Используется **отношение значений** для нормализации (`reward = price_reward * trade_reward`).
- Учёт "тренда" изменения цены (`price_reward` стимулирует удержание при росте цены) и завершения сделок (`trade_reward` сравнивает итоговую стоимость сделки с начальной).
3. **Параметризация поведения:**
- Параметры `window_size` (размер окна) и `max_shares` облегчают адаптацию среды под разные задачи.
4. **Полный `info`:**
- Добавлено `info`, включающее данные о действиях, текущей и предыдущей цене, всех типах наград, состоянии портфеля.
---
### **Пример использования среды**
Теперь можно протестировать обновлённую среду:
```python
import pandas as pd
import numpy as np
# Генерация фиктивных рыночных данных
data = pd.DataFrame({
"Open": np.random.rand(100) * 100,
"High": np.random.rand(100) * 100,
"Low": np.random.rand(100) * 100,
"Close": np.random.rand(100) * 100,
})
# Создание среды с ограничением на одну акцию
env = StockTradingEnv(data, initial_balance=1000, window_size=10, max_shares=1)
# Тестирование среды
state = env.reset()
total_reward = 0
for _ in range(50):
action = env.action_space.sample() # Случайное действие
state, reward, done, info = env.step(action) # Шаг в среде
# Вывод дополнительной информации
print(f"Step {info['step']} | Action: {info['action']} | Balance: {info['balance']:.2f} | Shares: {info['shares']} | Net Worth: {info['net_worth']:.2f} | Reward: {info['total_reward']:.4f}")
total_reward += reward
if done:
break
print(f"Total reward after test: {total_reward}")
```
---
### **Итоги**
1. **Среда поддерживает нормализацию наград, что помогает агенту избежать проблем с масштабами значений.**
2. **Лимит на количество акций (`max_shares`) позволяет создавать более реалистичные стратегии управления портфелем.**
3. **`info` включает все необходимые данные для анализа поведения агента в симуляции.**
Если хотите добавить дополнительные функции или усовершенствовать, дайте знать! 😊 🚀