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"])
|
model.load_state_dict(checkpoint["model_state_dict"])
|
||||||
return checkpoint
|
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 ---
|
# --- Backtest Environment ---
|
||||||
class BacktestEnvironment:
|
class BacktestEnvironment:
|
||||||
def __init__(self, candles_dict, base_tf, timeframes):
|
def __init__(self, candles_dict, base_tf, timeframes):
|
||||||
@ -284,7 +370,7 @@ class BacktestEnvironment:
|
|||||||
return len(self.candles_dict[self.base_tf])
|
return len(self.candles_dict[self.base_tf])
|
||||||
|
|
||||||
# --- Enhanced Training Loop ---
|
# --- 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):
|
for epoch in range(start_epoch, args.epochs):
|
||||||
state = env.reset()
|
state = env.reset()
|
||||||
total_loss = 0
|
total_loss = 0
|
||||||
@ -309,40 +395,13 @@ def train_on_historical_data(env, model, device, args, start_epoch, optimizer, s
|
|||||||
break
|
break
|
||||||
state = next_state
|
state = next_state
|
||||||
scheduler.step()
|
scheduler.step()
|
||||||
epoch_loss = total_loss/len(env)
|
epoch_loss = total_loss / len(env)
|
||||||
print(f"Epoch {epoch+1} Loss: {epoch_loss:.4f}")
|
print(f"Epoch {epoch+1} Loss: {epoch_loss:.4f}")
|
||||||
save_checkpoint(model, optimizer, epoch, total_loss)
|
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 ---
|
# --- Live Plotting Functions (For live mode) ---
|
||||||
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)
|
|
||||||
|
|
||||||
def live_preview_loop(candles, env):
|
def live_preview_loop(candles, env):
|
||||||
plt.ion()
|
plt.ion()
|
||||||
fig, ax = plt.subplots(figsize=(12, 6))
|
fig, ax = plt.subplots(figsize=(12, 6))
|
||||||
@ -406,7 +465,8 @@ async def main():
|
|||||||
print("Loaded optimizer state from checkpoint.")
|
print("Loaded optimizer state from checkpoint.")
|
||||||
else:
|
else:
|
||||||
print("No valid optimizer state found in checkpoint; starting fresh optimizer state.")
|
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':
|
elif args.mode == 'live':
|
||||||
load_best_checkpoint(model)
|
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