fixed showing all moves
This commit is contained in:
parent
44b02b4e7d
commit
b0a57c5330
105
realtime.py
105
realtime.py
@ -30,6 +30,9 @@ class BinanceHistoricalData:
|
|||||||
"""
|
"""
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.base_url = "https://api.binance.com/api/v3"
|
self.base_url = "https://api.binance.com/api/v3"
|
||||||
|
self.cache_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'cache')
|
||||||
|
if not os.path.exists(self.cache_dir):
|
||||||
|
os.makedirs(self.cache_dir)
|
||||||
|
|
||||||
def get_historical_candles(self, symbol, interval_seconds=3600, limit=1000):
|
def get_historical_candles(self, symbol, interval_seconds=3600, limit=1000):
|
||||||
"""
|
"""
|
||||||
@ -60,6 +63,14 @@ class BinanceHistoricalData:
|
|||||||
# Format symbol for Binance API (remove slash)
|
# Format symbol for Binance API (remove slash)
|
||||||
formatted_symbol = symbol.replace("/", "")
|
formatted_symbol = symbol.replace("/", "")
|
||||||
|
|
||||||
|
# Check if we have cached data first
|
||||||
|
cache_file = self._get_cache_filename(formatted_symbol, interval)
|
||||||
|
cached_data = self._load_from_cache(formatted_symbol, interval)
|
||||||
|
|
||||||
|
if cached_data is not None and len(cached_data) >= limit:
|
||||||
|
logger.info(f"Using cached historical data for {symbol} ({interval})")
|
||||||
|
return cached_data
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# Build URL for klines endpoint
|
# Build URL for klines endpoint
|
||||||
url = f"{self.base_url}/klines"
|
url = f"{self.base_url}/klines"
|
||||||
@ -93,14 +104,48 @@ class BinanceHistoricalData:
|
|||||||
# Sort by timestamp
|
# Sort by timestamp
|
||||||
df = df.sort_values("timestamp")
|
df = df.sort_values("timestamp")
|
||||||
|
|
||||||
|
# Save to cache for future use
|
||||||
|
self._save_to_cache(df, formatted_symbol, interval)
|
||||||
|
|
||||||
logger.info(f"Fetched {len(df)} candles for {symbol} ({interval})")
|
logger.info(f"Fetched {len(df)} candles for {symbol} ({interval})")
|
||||||
return df
|
return df
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"Error fetching historical data from Binance: {str(e)}")
|
logger.error(f"Error fetching historical data from Binance: {str(e)}")
|
||||||
|
# Return cached data if we have it, even if it's not enough
|
||||||
|
if cached_data is not None:
|
||||||
|
logger.warning(f"Using cached data instead (may be incomplete)")
|
||||||
|
return cached_data
|
||||||
# Return empty dataframe on error
|
# Return empty dataframe on error
|
||||||
return pd.DataFrame()
|
return pd.DataFrame()
|
||||||
|
|
||||||
|
def _get_cache_filename(self, symbol, interval):
|
||||||
|
"""Get filename for cache file"""
|
||||||
|
return os.path.join(self.cache_dir, f"{symbol}_{interval}_candles.csv")
|
||||||
|
|
||||||
|
def _load_from_cache(self, symbol, interval):
|
||||||
|
"""Load candles from cache file"""
|
||||||
|
try:
|
||||||
|
cache_file = self._get_cache_filename(symbol, interval)
|
||||||
|
if os.path.exists(cache_file):
|
||||||
|
df = pd.read_csv(cache_file)
|
||||||
|
df["timestamp"] = pd.to_datetime(df["timestamp"])
|
||||||
|
return df
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Error loading cached data: {str(e)}")
|
||||||
|
return None
|
||||||
|
|
||||||
|
def _save_to_cache(self, df, symbol, interval):
|
||||||
|
"""Save candles to cache file"""
|
||||||
|
try:
|
||||||
|
cache_file = self._get_cache_filename(symbol, interval)
|
||||||
|
df.to_csv(cache_file, index=False)
|
||||||
|
logger.info(f"Saved {len(df)} candles to cache: {cache_file}")
|
||||||
|
return True
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Error saving to cache: {str(e)}")
|
||||||
|
return False
|
||||||
|
|
||||||
def get_recent_trades(self, symbol, limit=1000):
|
def get_recent_trades(self, symbol, limit=1000):
|
||||||
"""Get recent trades for a symbol"""
|
"""Get recent trades for a symbol"""
|
||||||
formatted_symbol = symbol.replace("/", "")
|
formatted_symbol = symbol.replace("/", "")
|
||||||
@ -553,6 +598,7 @@ class TickStorage:
|
|||||||
try:
|
try:
|
||||||
# Load data for different timeframes
|
# Load data for different timeframes
|
||||||
timeframes = [
|
timeframes = [
|
||||||
|
(1, '1s'), # 1 second
|
||||||
(60, '1m'), # 1 minute
|
(60, '1m'), # 1 minute
|
||||||
(300, '5m'), # 5 minutes
|
(300, '5m'), # 5 minutes
|
||||||
(900, '15m'), # 15 minutes
|
(900, '15m'), # 15 minutes
|
||||||
@ -562,7 +608,22 @@ class TickStorage:
|
|||||||
]
|
]
|
||||||
|
|
||||||
for interval_seconds, interval_key in timeframes:
|
for interval_seconds, interval_key in timeframes:
|
||||||
df = historical_data.get_historical_candles(symbol, interval_seconds)
|
# Set appropriate limits based on timeframe
|
||||||
|
limit = 1000 # Default
|
||||||
|
if interval_seconds == 1:
|
||||||
|
limit = 500 # 1s is too much data, limit to 500
|
||||||
|
elif interval_seconds < 60:
|
||||||
|
limit = 750 # For seconds-level data
|
||||||
|
elif interval_seconds < 300:
|
||||||
|
limit = 1000 # 1m
|
||||||
|
elif interval_seconds < 900:
|
||||||
|
limit = 500 # 5m
|
||||||
|
elif interval_seconds < 3600:
|
||||||
|
limit = 300 # 15m
|
||||||
|
else:
|
||||||
|
limit = 200 # hourly/daily data
|
||||||
|
|
||||||
|
df = historical_data.get_historical_candles(symbol, interval_seconds, limit)
|
||||||
if df is not None and not df.empty:
|
if df is not None and not df.empty:
|
||||||
logger.info(f"Loaded {len(df)} historical candles for {symbol} ({interval_key})")
|
logger.info(f"Loaded {len(df)} historical candles for {symbol} ({interval_key})")
|
||||||
|
|
||||||
@ -578,12 +639,14 @@ class TickStorage:
|
|||||||
}
|
}
|
||||||
self.candles[interval_key].append(candle)
|
self.candles[interval_key].append(candle)
|
||||||
|
|
||||||
# Also use the close price to simulate ticks
|
# For 1m and above, also use the close price to simulate ticks
|
||||||
self.add_tick(
|
# but don't do this for seconds-level data as it creates too many ticks
|
||||||
price=row['close'],
|
if interval_seconds >= 60 and interval_key == '1m':
|
||||||
volume=row['volume'],
|
self.add_tick(
|
||||||
timestamp=row['timestamp']
|
price=row['close'],
|
||||||
)
|
volume=row['volume'],
|
||||||
|
timestamp=row['timestamp']
|
||||||
|
)
|
||||||
|
|
||||||
# Update latest price from most recent candle
|
# Update latest price from most recent candle
|
||||||
if len(df) > 0:
|
if len(df) > 0:
|
||||||
@ -904,14 +967,19 @@ class RealTimeChart:
|
|||||||
sell_times = []
|
sell_times = []
|
||||||
sell_prices = []
|
sell_prices = []
|
||||||
|
|
||||||
# Use only last 20 positions for clarity
|
# Use all positions for chart display
|
||||||
for position in self.positions[-20:]:
|
# Filter recent ones based on visible time range
|
||||||
if position.action == "BUY":
|
now = datetime.now()
|
||||||
buy_times.append(position.entry_timestamp)
|
time_limit = now - timedelta(hours=24) # Show at most 24h of trades
|
||||||
buy_prices.append(position.entry_price)
|
|
||||||
elif position.action == "SELL" and position.exit_timestamp:
|
for position in self.positions:
|
||||||
sell_times.append(position.exit_timestamp)
|
if position.entry_timestamp > time_limit:
|
||||||
sell_prices.append(position.exit_price)
|
if position.action == "BUY":
|
||||||
|
buy_times.append(position.entry_timestamp)
|
||||||
|
buy_prices.append(position.entry_price)
|
||||||
|
elif position.action == "SELL" and position.exit_timestamp:
|
||||||
|
sell_times.append(position.exit_timestamp)
|
||||||
|
sell_prices.append(position.exit_price)
|
||||||
|
|
||||||
# Add buy markers (green triangles pointing up)
|
# Add buy markers (green triangles pointing up)
|
||||||
if buy_times:
|
if buy_times:
|
||||||
@ -1112,14 +1180,17 @@ class RealTimeChart:
|
|||||||
winning_trades = sum(1 for p in self.positions if p.pnl and p.pnl > 0)
|
winning_trades = sum(1 for p in self.positions if p.pnl and p.pnl > 0)
|
||||||
win_rate = winning_trades / total_trades * 100 if total_trades > 0 else 0
|
win_rate = winning_trades / total_trades * 100 if total_trades > 0 else 0
|
||||||
|
|
||||||
|
# Format display colors for PnL
|
||||||
|
pnl_color = "green" if self.accumulative_pnl >= 0 else "red"
|
||||||
|
|
||||||
summary_row = html.Tr([
|
summary_row = html.Tr([
|
||||||
html.Td("SUMMARY", colSpan=2, style={"fontWeight": "bold"}),
|
html.Td("SUMMARY", colSpan=2, style={"fontWeight": "bold"}),
|
||||||
html.Td(f"Trades: {total_trades}"),
|
html.Td(f"Trades: {total_trades}"),
|
||||||
html.Td(f"Win Rate: {win_rate:.1f}%"),
|
html.Td(f"Win Rate: {win_rate:.1f}%"),
|
||||||
html.Td("Total PnL:", style={"fontWeight": "bold"}),
|
html.Td("Total PnL:", style={"fontWeight": "bold"}),
|
||||||
html.Td(f"${self.accumulative_pnl:.2f}",
|
html.Td(f"${self.accumulative_pnl:.2f}",
|
||||||
style={"color": "green" if self.accumulative_pnl >= 0 else "red", "fontWeight": "bold"}),
|
style={"color": pnl_color, "fontWeight": "bold"}),
|
||||||
html.Td("")
|
html.Td(f"Balance: ${self.current_balance:.2f}")
|
||||||
], style={"backgroundColor": "rgba(80, 80, 80, 0.3)"})
|
], style={"backgroundColor": "rgba(80, 80, 80, 0.3)"})
|
||||||
|
|
||||||
# Create the table with improved styling
|
# Create the table with improved styling
|
||||||
|
@ -516,17 +516,27 @@ class RLTrainingIntegrator:
|
|||||||
if len(self.price_history) > self.price_history_max_len:
|
if len(self.price_history) > self.price_history_max_len:
|
||||||
self.price_history = self.price_history[-self.price_history_max_len:]
|
self.price_history = self.price_history[-self.price_history_max_len:]
|
||||||
|
|
||||||
|
# Normalize rewards to be realistic for crypto trading (smaller values)
|
||||||
|
normalized_reward = reward * 0.1 # Scale down rewards
|
||||||
|
if abs(normalized_reward) > 5.0: # Cap maximum reward value
|
||||||
|
normalized_reward = 5.0 if normalized_reward > 0 else -5.0
|
||||||
|
|
||||||
# Update session PnL and balance
|
# Update session PnL and balance
|
||||||
self.session_step += 1
|
self.session_step += 1
|
||||||
self.session_pnl += reward
|
self.session_pnl += normalized_reward
|
||||||
|
|
||||||
# Increase balance based on reward
|
# Increase balance based on reward - cap to reasonable values
|
||||||
self.session_balance += reward
|
self.session_balance += normalized_reward
|
||||||
|
self.session_balance = min(self.session_balance, 1000.0) # Cap maximum balance
|
||||||
|
self.session_balance = max(self.session_balance, 0.0) # Prevent negative balance
|
||||||
|
|
||||||
# Update chart's accumulativePnL and balance if available
|
# Update chart's accumulativePnL and balance if available
|
||||||
if self.chart:
|
if self.chart:
|
||||||
if hasattr(self.chart, 'accumulative_pnl'):
|
if hasattr(self.chart, 'accumulative_pnl'):
|
||||||
self.chart.accumulative_pnl = self.session_pnl
|
self.chart.accumulative_pnl = self.session_pnl
|
||||||
|
# Cap accumulated PnL to reasonable values
|
||||||
|
self.chart.accumulative_pnl = min(self.chart.accumulative_pnl, 500.0)
|
||||||
|
self.chart.accumulative_pnl = max(self.chart.accumulative_pnl, -100.0)
|
||||||
|
|
||||||
if hasattr(self.chart, 'current_balance'):
|
if hasattr(self.chart, 'current_balance'):
|
||||||
self.chart.current_balance = self.session_balance
|
self.chart.current_balance = self.session_balance
|
||||||
@ -751,7 +761,7 @@ def _add_trade_compat(chart, price, timestamp, amount, pnl=0.0, action="BUY"):
|
|||||||
position.close(price, timestamp)
|
position.close(price, timestamp)
|
||||||
# Use realistic PnL values rather than the enormous ones from the model
|
# Use realistic PnL values rather than the enormous ones from the model
|
||||||
# Cap PnL to reasonable values based on position size and price
|
# Cap PnL to reasonable values based on position size and price
|
||||||
max_reasonable_pnl = price * amount * 0.10 # Max 10% profit
|
max_reasonable_pnl = price * amount * 0.05 # Max 5% profit per trade
|
||||||
if abs(pnl) > max_reasonable_pnl:
|
if abs(pnl) > max_reasonable_pnl:
|
||||||
if pnl > 0:
|
if pnl > 0:
|
||||||
pnl = max_reasonable_pnl * 0.8 # Positive but reasonable
|
pnl = max_reasonable_pnl * 0.8 # Positive but reasonable
|
||||||
@ -762,11 +772,14 @@ def _add_trade_compat(chart, price, timestamp, amount, pnl=0.0, action="BUY"):
|
|||||||
# Update chart's accumulated PnL if available
|
# Update chart's accumulated PnL if available
|
||||||
if hasattr(chart, 'accumulative_pnl'):
|
if hasattr(chart, 'accumulative_pnl'):
|
||||||
chart.accumulative_pnl += pnl
|
chart.accumulative_pnl += pnl
|
||||||
|
# Cap accumulated PnL to reasonable values
|
||||||
|
chart.accumulative_pnl = min(chart.accumulative_pnl, 500.0)
|
||||||
|
chart.accumulative_pnl = max(chart.accumulative_pnl, -100.0)
|
||||||
|
|
||||||
# Add to positions list, keeping only the last 10 if we have more
|
# Add to positions list, keeping only the last 200 for chart display
|
||||||
chart.positions.append(position)
|
chart.positions.append(position)
|
||||||
if len(chart.positions) > 10:
|
if len(chart.positions) > 200:
|
||||||
chart.positions = chart.positions[-10:]
|
chart.positions = chart.positions[-200:]
|
||||||
|
|
||||||
logger.info(f"Added {action} trade: price={price:.2f}, amount={amount}, pnl={pnl:.2f}")
|
logger.info(f"Added {action} trade: price={price:.2f}, amount={amount}, pnl={pnl:.2f}")
|
||||||
return True
|
return True
|
||||||
|
Loading…
x
Reference in New Issue
Block a user