hft-env / static /index.html
JonathanShiju12's picture
Upload folder using huggingface_hub
f5e8b69 verified
Raw
History Blame Contribute Delete
15.1 kB
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>HFT Environment Dashboard</title>
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<style>
:root {
--bg-color: #121212;
--panel-bg: #1e1e1e;
--text-color: #e0e0e0;
--muted-text: #a0a0a0;
--border-color: #2d2d2d;
--btn-bg: #333333;
--btn-hover: #444444;
--success-color: #81c784;
--error-color: #e57373;
--chart-color-1: #81c784;
--font-family: "Inter", "Helvetica Neue", Helvetica, Arial, sans-serif;
}
*,
*::before,
*::after {
box-sizing: border-box;
}
body {
font-family: var(--font-family);
background-color: var(--bg-color);
color: var(--text-color);
margin: 0;
padding: 32px;
display: flex;
flex-direction: column;
min-height: 100vh;
font-weight: 300;
}
header {
margin-bottom: 32px;
padding-bottom: 16px;
border-bottom: 1px solid var(--border-color);
}
h1 {
margin: 0;
font-size: 1.25rem;
font-weight: 400;
letter-spacing: 0.5px;
}
.container {
display: grid;
grid-template-columns: 320px 1fr;
gap: 32px;
flex: 1;
}
.panel {
background-color: var(--panel-bg);
border: 1px solid var(--border-color);
border-radius: 4px;
padding: 24px;
margin-bottom: 24px;
width: 100%;
}
.panel h2 {
margin-top: 0;
margin-bottom: 20px;
font-size: 1rem;
font-weight: 500;
color: var(--text-color);
}
.form-group {
margin-bottom: 16px;
display: flex;
flex-direction: column;
width: 100%;
}
label {
font-size: 0.75rem;
margin-bottom: 6px;
color: var(--muted-text);
text-transform: uppercase;
letter-spacing: 0.5px;
}
input,
select {
background-color: var(--bg-color);
border: 1px solid var(--border-color);
color: var(--text-color);
padding: 10px;
border-radius: 2px;
font-family: inherit;
font-size: 0.875rem;
width: 100%;
}
input:focus,
select:focus {
outline: none;
border-color: #555555;
}
button {
background-color: var(--btn-bg);
border: 1px solid var(--border-color);
padding: 10px 16px;
border-radius: 2px;
color: var(--text-color);
font-weight: 400;
cursor: pointer;
width: 100%;
transition: background-color 0.15s ease;
font-family: inherit;
margin-top: 8px;
}
button:hover {
background-color: var(--btn-hover);
}
.output-section {
display: flex;
flex-direction: column;
gap: 24px;
min-width: 0;
}
.chart-container {
position: relative;
height: 300px;
width: 100%;
}
.output-box {
background-color: var(--panel-bg);
border: 1px solid var(--border-color);
border-radius: 4px;
display: flex;
flex-direction: column;
width: 100%;
overflow: hidden;
}
.output-header {
padding: 16px 20px;
border-bottom: 1px solid var(--border-color);
font-size: 0.875rem;
font-weight: 500;
display: flex;
justify-content: space-between;
align-items: center;
}
pre {
margin: 0;
padding: 20px;
overflow-x: auto;
color: var(--muted-text);
font-size: 0.85rem;
white-space: pre-wrap;
word-wrap: break-word;
font-family: "Courier New", Courier, monospace;
}
.log-pre {
max-height: 150px;
overflow-y: auto;
color: #b0bec5;
}
.status {
font-size: 0.75rem;
padding: 4px 8px;
border-radius: 2px;
text-transform: uppercase;
letter-spacing: 0.5px;
}
.grid-2-col {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 12px;
width: 100%;
}
</style>
</head>
<body>
<header>
<h1>HFT Environment Dashboard</h1>
</header>
<div class="container">
<div class="controls-section">
<div class="panel">
<h2>Reset Environment</h2>
<div class="form-group">
<label for="task">Task</label>
<select id="task">
<option value="basic_execution">Basic Execution</option>
<option value="false_signal">False Signal</option>
<option value="conflicting_signal">Conflicting Signal</option>
<option value="flash_crash">Flash Crash</option>
</select>
</div>
<div class="grid-2-col">
<div class="form-group">
<label for="max_steps">Max Steps</label>
<input type="number" id="max_steps" placeholder="Optional" />
</div>
<div class="form-group">
<label for="tick_size">Tick Size</label>
<input
type="number"
step="0.01"
id="tick_size"
placeholder="Optional"
/>
</div>
<div class="form-group">
<label for="inventory">Inventory</label>
<input type="number" id="inventory" placeholder="Optional" />
</div>
<div class="form-group">
<label for="cash">Cash</label>
<input
type="number"
step="0.01"
id="cash"
placeholder="Optional"
/>
</div>
</div>
<button onclick="resetEnvironment()">Reset Environment</button>
</div>
<div class="panel">
<h2>Take Action (Step)</h2>
<div class="grid-2-col">
<div class="form-group">
<label for="limit_buy_price">Limit Buy Price</label>
<input type="number" step="0.01" id="limit_buy_price" />
</div>
<div class="form-group">
<label for="limit_buy_size">Limit Buy Size</label>
<input type="number" id="limit_buy_size" />
</div>
<div class="form-group">
<label for="limit_ask_price">Limit Ask Price</label>
<input type="number" step="0.01" id="limit_ask_price" />
</div>
<div class="form-group">
<label for="limit_ask_size">Limit Ask Size</label>
<input type="number" id="limit_ask_size" />
</div>
<div class="form-group">
<label for="market_buy_size">Market Buy Size</label>
<input type="number" id="market_buy_size" />
</div>
<div class="form-group">
<label for="market_ask_size">Market Ask Size</label>
<input type="number" id="market_ask_size" />
</div>
</div>
<div class="form-group">
<label for="cancel_order_id">Cancel Order ID</label>
<input type="text" id="cancel_order_id" placeholder="Optional" />
</div>
<button onclick="stepEnvironment()">Execute Step</button>
</div>
<div class="panel">
<h2>Environment State</h2>
<button onclick="fetchState()">Refresh State</button>
</div>
</div>
<div class="output-section">
<div class="panel">
<h2>Reward per Time Step</h2>
<div class="chart-container">
<canvas id="rewardChart"></canvas>
</div>
</div>
<div class="grid-2-col">
<div class="output-box">
<div class="output-header">
<span>Observation</span>
<span id="obs_status" class="status">Waiting</span>
</div>
<pre id="observation_output">No data yet.</pre>
</div>
<div class="output-box">
<div class="output-header">
<span>State</span>
<span id="state_status" class="status">Waiting</span>
</div>
<pre id="state_output">No data yet.</pre>
</div>
</div>
<div class="output-box">
<div class="output-header">
<span>Action Log</span>
</div>
<pre id="action_log" class="log-pre">System Initialized.</pre>
</div>
</div>
</div>
<script>
const baseUrl = "{{ api_url }}";
let chartInstance = null;
function initChart() {
const ctx = document.getElementById("rewardChart").getContext("2d");
Chart.defaults.color = "#a0a0a0";
Chart.defaults.font.family = "'Inter', sans-serif";
chartInstance = new Chart(ctx, {
type: "line",
data: {
labels: [],
datasets: [
{
label: "Reward",
data: [],
borderColor: "#81c784",
backgroundColor: "rgba(129, 199, 132, 0.1)",
borderWidth: 2,
tension: 0.1,
fill: true,
pointRadius: 3,
},
],
},
options: {
responsive: true,
maintainAspectRatio: false,
scales: {
x: {
title: { display: true, text: "Time" },
grid: { color: "#2d2d2d" },
},
y: {
title: { display: true, text: "Reward" },
grid: { color: "#2d2d2d" },
},
},
plugins: { legend: { display: false } },
},
});
}
function updateOutput(elementId, statusId, data, isError = false) {
const el = document.getElementById(elementId);
const statusEl = document.getElementById(statusId);
el.textContent = JSON.stringify(data, null, 2);
if (isError) {
el.style.color = "var(--error-color)";
statusEl.textContent = "Error";
} else {
el.style.color = "var(--text-color)";
statusEl.textContent = "Success";
}
}
function appendLog(message) {
const logBox = document.getElementById("action_log");
const timestamp = new Date().toLocaleTimeString("en-US", {
hour12: false,
});
logBox.textContent += `\n[${timestamp}] ${message}`;
logBox.scrollTop = logBox.scrollHeight;
}
function getTask() {
return document.getElementById("task").value;
}
async function resetEnvironment() {
const task = getTask();
let url = `${baseUrl}/reset?task=${task}`;
const params = ["max_steps", "tick_size", "inventory", "cash"];
params.forEach((param) => {
const val = document.getElementById(param).value;
if (val) {
url += `&${param}=${val}`;
}
});
try {
const response = await fetch(url, {
method: "POST",
credentials: "include",
});
const data = await response.json();
if (!response.ok) throw data;
chartInstance.data.labels = [];
chartInstance.data.datasets[0].data = [];
chartInstance.update();
appendLog(`RESET - Task: ${task}`);
updateOutput("observation_output", "obs_status", data);
await fetchState();
} catch (error) {
appendLog(`ERROR - Failed to reset environment`);
updateOutput("observation_output", "obs_status", error, true);
}
}
async function stepEnvironment() {
const task = getTask();
const actionData = {};
let logActionStr = "";
const numFields = [
"limit_buy_price",
"limit_buy_size",
"limit_ask_price",
"limit_ask_size",
"market_buy_size",
"market_ask_size",
];
numFields.forEach((field) => {
const val = document.getElementById(field).value;
if (val !== "") actionData[field] = Number(val);
});
const cancelId = document.getElementById("cancel_order_id").value;
if (cancelId !== "") actionData["cancel_order_id"] = cancelId;
if (actionData.limit_buy_size && actionData.limit_buy_price) {
logActionStr = `LIMIT BUY ${actionData.limit_buy_size} @ ${actionData.limit_buy_price}`;
} else if (actionData.limit_ask_size && actionData.limit_ask_price) {
logActionStr = `LIMIT ASK ${actionData.limit_ask_size} @ ${actionData.limit_ask_price}`;
} else if (actionData.market_buy_size) {
logActionStr = `MARKET BUY ${actionData.market_buy_size}`;
} else if (actionData.market_ask_size) {
logActionStr = `MARKET ASK ${actionData.market_ask_size}`;
} else if (actionData.cancel_order_id) {
logActionStr = `CANCEL ${actionData.cancel_order_id}`;
} else {
logActionStr = `ACTION: ${JSON.stringify(actionData)}`;
}
try {
const response = await fetch(`${baseUrl}/step?task=${task}`, {
method: "POST",
headers: { "Content-Type": "application/json" },
credentials: "include",
body: JSON.stringify(actionData),
});
const data = await response.json();
if (!response.ok) throw data;
if (data.time !== undefined && data.reward !== undefined) {
chartInstance.data.labels.push(data.time.toFixed(2));
chartInstance.data.datasets[0].data.push(data.reward);
chartInstance.update();
}
appendLog(
`${logActionStr} -> Reward: ${data.reward !== undefined ? data.reward : "N/A"}`,
);
updateOutput("observation_output", "obs_status", data);
await fetchState();
} catch (error) {
appendLog(`ERROR - Failed to execute: ${logActionStr}`);
updateOutput("observation_output", "obs_status", error, true);
}
}
async function fetchState() {
const task = getTask();
try {
const response = await fetch(`${baseUrl}/state?task=${task}`, {
method: "GET",
credentials: "include",
});
const data = await response.json();
if (!response.ok) throw data;
updateOutput("state_output", "state_status", data);
} catch (error) {
updateOutput("state_output", "state_status", error, true);
}
}
window.onload = initChart;
</script>
</body>
</html>