RayMelius Claude Sonnet 4.6 commited on
Commit
aeb86d9
·
1 Parent(s): fb7c4e4

Price chart: narrower volume bars, right-side volume Y-axis; UI polish

Browse files

- Volume bars width reduced to 35% of slot (was 65%) for cleaner chart
- Volume Y-axis labels added on right side (0, 50%, max) with k-suffix
- pad.right widened to 46px to accommodate volume labels
- Trading Statistics thead row: background #f0f0f0 (matches Orders/Trades)
- Auto mode: End of Day button stays enabled when session is active
- Default mode changed to Automatic (backend + frontend)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

dashboard/dashboard.py CHANGED
@@ -20,7 +20,7 @@ sse_clients = []
20
  sse_clients_lock = threading.Lock()
21
 
22
  # Session state
23
- session_state = {"active": False, "start_time": None, "suspended": False, "mode": "manual"}
24
 
25
  SCHEDULE_FILE = os.getenv("SCHEDULE_FILE", "/app/shared_data/market_schedule.txt")
26
 
 
20
  sse_clients_lock = threading.Lock()
21
 
22
  # Session state
23
+ session_state = {"active": False, "start_time": None, "suspended": False, "mode": "automatic"}
24
 
25
  SCHEDULE_FILE = os.getenv("SCHEDULE_FILE", "/app/shared_data/market_schedule.txt")
26
 
dashboard/templates/index.html CHANGED
@@ -201,9 +201,9 @@
201
  Trading Dashboard
202
  <span id="status" class="status connecting"><span class="dot"></span><span id="status-text">Connecting...</span></span>
203
  <span id="session-badge" class="status idle"><span class="dot"></span><span id="session-text">IDLE</span></span>
204
- <button id="day-btn" onclick="toggleDay()" class="btn-day btn-start">Start of Day</button>
205
  <button id="suspend-btn" onclick="toggleSuspend()" class="btn-day btn-suspend" disabled>Suspend</button>
206
- <button id="mode-btn" onclick="toggleMode()" class="btn-day btn-manual">Manual</button>
207
  <a href="/fix/" style="margin-left:auto; padding:4px 14px; background:#6c757d; color:#fff; border-radius:20px; font-size:12px; font-weight:bold; text-decoration:none;">FIX UI</a>
208
  </h1>
209
  <div class="container">
@@ -310,7 +310,7 @@
310
  <div id="stats-container" style="flex-grow:1; overflow-y:auto; padding: 10px;">
311
  <table id="stats-table" style="width:100%; margin-bottom:10px; font-size:12px;">
312
  <thead>
313
- <tr>
314
  <th>Symbol</th>
315
  <th>Trades</th>
316
  <th>Volume</th>
@@ -764,7 +764,7 @@
764
  return;
765
  }
766
 
767
- const pad = { top: 18, right: 12, bottom: 32, left: 55 };
768
  const W = canvas.width - pad.left - pad.right;
769
  const H = canvas.height - pad.top - pad.bottom;
770
  const priceH = H * 0.70;
@@ -778,9 +778,10 @@
778
  const maxV = Math.max(...points.map(p => p.volume), 1);
779
  const toY = p => priceY + priceH - ((p - minP) / (maxP - minP)) * priceH;
780
 
781
- const n = points.length;
782
- const slotW = W / n;
783
- const bodyW = Math.max(1, Math.floor(slotW * 0.65));
 
784
 
785
  // Price grid
786
  ctx.strokeStyle = "#eee"; ctx.lineWidth = 1;
@@ -797,10 +798,19 @@
797
 
798
  // Volume bars
799
  points.forEach((p, i) => {
800
- const x = pad.left + i * slotW + (slotW - bodyW) / 2;
801
  const bh = (p.volume / maxV) * volH;
802
  ctx.fillStyle = p.close >= p.open ? "rgba(38,166,154,0.4)" : "rgba(239,83,80,0.4)";
803
- ctx.fillRect(x, volY + volH - bh, bodyW, bh);
 
 
 
 
 
 
 
 
 
804
  });
805
 
806
  // Candlestick wicks + bodies
@@ -1052,7 +1062,7 @@
1052
 
1053
  let _sessionActive = false;
1054
  let _sessionSuspended = false;
1055
- let _sessionMode = "manual";
1056
 
1057
  function updateSessionBadge(active, suspended) {
1058
  const badge = document.getElementById("session-badge");
@@ -1070,7 +1080,7 @@
1070
  btn.className = "btn-day btn-suspend";
1071
  dayBtn.textContent = "Start of Day";
1072
  dayBtn.className = "btn-day btn-start";
1073
- dayBtn.disabled = isAuto;
1074
  } else if (suspended) {
1075
  badge.className = "status suspended";
1076
  text.textContent = "PAUSED";
@@ -1079,7 +1089,7 @@
1079
  btn.className = "btn-day btn-resume";
1080
  dayBtn.textContent = "End of Day";
1081
  dayBtn.className = "btn-day btn-end";
1082
- dayBtn.disabled = isAuto;
1083
  } else {
1084
  badge.className = "status active";
1085
  text.textContent = "ACTIVE";
@@ -1088,7 +1098,7 @@
1088
  btn.className = "btn-day btn-suspend";
1089
  dayBtn.textContent = "End of Day";
1090
  dayBtn.className = "btn-day btn-end";
1091
- dayBtn.disabled = isAuto;
1092
  }
1093
  }
1094
 
 
201
  Trading Dashboard
202
  <span id="status" class="status connecting"><span class="dot"></span><span id="status-text">Connecting...</span></span>
203
  <span id="session-badge" class="status idle"><span class="dot"></span><span id="session-text">IDLE</span></span>
204
+ <button id="day-btn" onclick="toggleDay()" class="btn-day btn-start" disabled>Start of Day</button>
205
  <button id="suspend-btn" onclick="toggleSuspend()" class="btn-day btn-suspend" disabled>Suspend</button>
206
+ <button id="mode-btn" onclick="toggleMode()" class="btn-day btn-automatic">Automatic</button>
207
  <a href="/fix/" style="margin-left:auto; padding:4px 14px; background:#6c757d; color:#fff; border-radius:20px; font-size:12px; font-weight:bold; text-decoration:none;">FIX UI</a>
208
  </h1>
209
  <div class="container">
 
310
  <div id="stats-container" style="flex-grow:1; overflow-y:auto; padding: 10px;">
311
  <table id="stats-table" style="width:100%; margin-bottom:10px; font-size:12px;">
312
  <thead>
313
+ <tr style="background:#f0f0f0;">
314
  <th>Symbol</th>
315
  <th>Trades</th>
316
  <th>Volume</th>
 
764
  return;
765
  }
766
 
767
+ const pad = { top: 18, right: 46, bottom: 32, left: 55 };
768
  const W = canvas.width - pad.left - pad.right;
769
  const H = canvas.height - pad.top - pad.bottom;
770
  const priceH = H * 0.70;
 
778
  const maxV = Math.max(...points.map(p => p.volume), 1);
779
  const toY = p => priceY + priceH - ((p - minP) / (maxP - minP)) * priceH;
780
 
781
+ const n = points.length;
782
+ const slotW = W / n;
783
+ const bodyW = Math.max(1, Math.floor(slotW * 0.65));
784
+ const volBarW = Math.max(1, Math.floor(slotW * 0.35));
785
 
786
  // Price grid
787
  ctx.strokeStyle = "#eee"; ctx.lineWidth = 1;
 
798
 
799
  // Volume bars
800
  points.forEach((p, i) => {
801
+ const x = pad.left + i * slotW + (slotW - volBarW) / 2;
802
  const bh = (p.volume / maxV) * volH;
803
  ctx.fillStyle = p.close >= p.open ? "rgba(38,166,154,0.4)" : "rgba(239,83,80,0.4)";
804
+ ctx.fillRect(x, volY + volH - bh, volBarW, bh);
805
+ });
806
+
807
+ // Volume Y-axis labels (right side)
808
+ ctx.fillStyle = "#888"; ctx.font = "9px Arial"; ctx.textAlign = "left";
809
+ [1.0, 0.5, 0.0].forEach(frac => {
810
+ const val = Math.round(maxV * frac);
811
+ const y = volY + volH * (1 - frac);
812
+ const lbl = val >= 1000 ? (val / 1000).toFixed(1) + "k" : val.toString();
813
+ ctx.fillText(lbl, canvas.width - pad.right + 3, y + 3);
814
  });
815
 
816
  // Candlestick wicks + bodies
 
1062
 
1063
  let _sessionActive = false;
1064
  let _sessionSuspended = false;
1065
+ let _sessionMode = "automatic";
1066
 
1067
  function updateSessionBadge(active, suspended) {
1068
  const badge = document.getElementById("session-badge");
 
1080
  btn.className = "btn-day btn-suspend";
1081
  dayBtn.textContent = "Start of Day";
1082
  dayBtn.className = "btn-day btn-start";
1083
+ dayBtn.disabled = isAuto; // auto handles start; manual can't
1084
  } else if (suspended) {
1085
  badge.className = "status suspended";
1086
  text.textContent = "PAUSED";
 
1089
  btn.className = "btn-day btn-resume";
1090
  dayBtn.textContent = "End of Day";
1091
  dayBtn.className = "btn-day btn-end";
1092
+ dayBtn.disabled = false; // always allow manual end
1093
  } else {
1094
  badge.className = "status active";
1095
  text.textContent = "ACTIVE";
 
1098
  btn.className = "btn-day btn-suspend";
1099
  dayBtn.textContent = "End of Day";
1100
  dayBtn.className = "btn-day btn-end";
1101
+ dayBtn.disabled = false; // always allow manual end
1102
  }
1103
  }
1104