Html (kind of) chart
This commit is contained in:
parent
c9f7367bcf
commit
fbff9c37a2
@ -215,6 +215,92 @@ def load_best_checkpoint(model, best_dir=BEST_DIR):
|
||||
model.load_state_dict(checkpoint["model_state_dict"])
|
||||
return checkpoint
|
||||
|
||||
# --- Live HTML Chart Update ---
|
||||
def update_live_html(candles, trade_history, epoch):
|
||||
"""
|
||||
Generate a chart image with buy/sell markers and a dotted line between open and close,
|
||||
then embed it in a simple HTML page that auto-refreshes.
|
||||
"""
|
||||
from io import BytesIO
|
||||
import base64
|
||||
|
||||
fig, ax = plt.subplots(figsize=(12, 6))
|
||||
update_live_chart(ax, candles, trade_history)
|
||||
ax.set_title(f"Live Trading Chart - Epoch {epoch}")
|
||||
buf = BytesIO()
|
||||
fig.savefig(buf, format='png')
|
||||
plt.close(fig)
|
||||
buf.seek(0)
|
||||
image_base64 = base64.b64encode(buf.getvalue()).decode('utf-8')
|
||||
html_content = f"""
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="refresh" content="10">
|
||||
<title>Live Trading Chart - Epoch {epoch}</title>
|
||||
<style>
|
||||
body {{
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
background-color: #f4f4f4;
|
||||
}}
|
||||
.chart-container {{
|
||||
text-align: center;
|
||||
}}
|
||||
img {{
|
||||
max-width: 100%;
|
||||
height: auto;
|
||||
}}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="chart-container">
|
||||
<h2>Live Trading Chart - Epoch {epoch}</h2>
|
||||
<img src="data:image/png;base64,{image_base64}" alt="Live Chart"/>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
"""
|
||||
with open("live_chart.html", "w") as f:
|
||||
f.write(html_content)
|
||||
print("Updated live_chart.html.")
|
||||
|
||||
# --- Chart Drawing Helpers (used by both live preview and HTML update) ---
|
||||
def update_live_chart(ax, candles, trade_history):
|
||||
"""
|
||||
Plot the chart with close price, buy and sell markers, and dotted lines joining buy/sell entry/exit.
|
||||
"""
|
||||
ax.clear()
|
||||
close_prices = [candle["close"] for candle in candles]
|
||||
x = list(range(len(close_prices)))
|
||||
ax.plot(x, close_prices, label="Close Price", color="black", linewidth=1)
|
||||
buy_label_added = False
|
||||
sell_label_added = False
|
||||
for trade in trade_history:
|
||||
in_idx = trade["entry_index"]
|
||||
out_idx = trade["exit_index"]
|
||||
in_price = trade["entry_price"]
|
||||
out_price = trade["exit_price"]
|
||||
if not buy_label_added:
|
||||
ax.plot(in_idx, in_price, marker="^", color="green", markersize=10, label="BUY")
|
||||
buy_label_added = True
|
||||
else:
|
||||
ax.plot(in_idx, in_price, marker="^", color="green", markersize=10)
|
||||
if not sell_label_added:
|
||||
ax.plot(out_idx, out_price, marker="v", color="red", markersize=10, label="SELL")
|
||||
sell_label_added = True
|
||||
else:
|
||||
ax.plot(out_idx, out_price, marker="v", color="red", markersize=10)
|
||||
ax.plot([in_idx, out_idx], [in_price, out_price], linestyle="dotted", color="blue")
|
||||
ax.set_xlabel("Candle Index")
|
||||
ax.set_ylabel("Price")
|
||||
ax.legend()
|
||||
ax.grid(True)
|
||||
|
||||
# --- Backtest Environment ---
|
||||
class BacktestEnvironment:
|
||||
def __init__(self, candles_dict, base_tf, timeframes):
|
||||
@ -284,7 +370,7 @@ class BacktestEnvironment:
|
||||
return len(self.candles_dict[self.base_tf])
|
||||
|
||||
# --- Enhanced Training Loop ---
|
||||
def train_on_historical_data(env, model, device, args, start_epoch, optimizer, scheduler):
|
||||
def train_on_historical_data(env, model, device, args, start_epoch, optimizer, scheduler, base_candles):
|
||||
for epoch in range(start_epoch, args.epochs):
|
||||
state = env.reset()
|
||||
total_loss = 0
|
||||
@ -312,37 +398,10 @@ def train_on_historical_data(env, model, device, args, start_epoch, optimizer, s
|
||||
epoch_loss = total_loss / len(env)
|
||||
print(f"Epoch {epoch+1} Loss: {epoch_loss:.4f}")
|
||||
save_checkpoint(model, optimizer, epoch, total_loss)
|
||||
# Update the live HTML file with the current epoch chart
|
||||
update_live_html(base_candles, env.trade_history, epoch+1)
|
||||
|
||||
# --- Live Plotting Functions ---
|
||||
def update_live_chart(ax, candles, trade_history):
|
||||
ax.clear()
|
||||
close_prices = [candle["close"] for candle in candles]
|
||||
x = list(range(len(close_prices)))
|
||||
ax.plot(x, close_prices, label="Close Price", color="black", linewidth=1)
|
||||
buy_label_added = False
|
||||
sell_label_added = False
|
||||
for trade in trade_history:
|
||||
in_idx = trade["entry_index"]
|
||||
out_idx = trade["exit_index"]
|
||||
in_price = trade["entry_price"]
|
||||
out_price = trade["exit_price"]
|
||||
if not buy_label_added:
|
||||
ax.plot(in_idx, in_price, marker="^", color="green", markersize=10, label="BUY")
|
||||
buy_label_added = True
|
||||
else:
|
||||
ax.plot(in_idx, in_price, marker="^", color="green", markersize=10)
|
||||
if not sell_label_added:
|
||||
ax.plot(out_idx, out_price, marker="v", color="red", markersize=10, label="SELL")
|
||||
sell_label_added = True
|
||||
else:
|
||||
ax.plot(out_idx, out_price, marker="v", color="red", markersize=10)
|
||||
ax.plot([in_idx, out_idx], [in_price, out_price], linestyle="dotted", color="blue")
|
||||
ax.set_title("Live Trading Chart")
|
||||
ax.set_xlabel("Candle Index")
|
||||
ax.set_ylabel("Price")
|
||||
ax.legend()
|
||||
ax.grid(True)
|
||||
|
||||
# --- Live Plotting Functions (For live mode) ---
|
||||
def live_preview_loop(candles, env):
|
||||
plt.ion()
|
||||
fig, ax = plt.subplots(figsize=(12, 6))
|
||||
@ -406,7 +465,8 @@ async def main():
|
||||
print("Loaded optimizer state from checkpoint.")
|
||||
else:
|
||||
print("No valid optimizer state found in checkpoint; starting fresh optimizer state.")
|
||||
train_on_historical_data(env, model, device, args, start_epoch, optimizer, scheduler)
|
||||
# Pass base candles from the base timeframe for HTML chart updates.
|
||||
train_on_historical_data(env, model, device, args, start_epoch, optimizer, scheduler, candles_dict[base_tf])
|
||||
|
||||
elif args.mode == 'live':
|
||||
load_best_checkpoint(model)
|
||||
|
32
crypto/brian/live_chart.html
Normal file
32
crypto/brian/live_chart.html
Normal file
File diff suppressed because one or more lines are too long
Loading…
x
Reference in New Issue
Block a user