Update index.html
Browse files- index.html +77 -19
index.html
CHANGED
|
@@ -270,31 +270,89 @@
|
|
| 270 |
}
|
| 271 |
}
|
| 272 |
|
| 273 |
-
|
| 274 |
-
|
| 275 |
-
|
| 276 |
-
|
| 277 |
-
|
| 278 |
-
|
| 279 |
-
|
| 280 |
-
|
| 281 |
-
|
| 282 |
-
|
| 283 |
-
|
| 284 |
-
|
| 285 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 286 |
} else {
|
| 287 |
-
|
| 288 |
-
|
| 289 |
-
state.cash += (cost - COMMISSION);
|
| 290 |
-
if (state.shares === 0) state.avgCost = 0;
|
| 291 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 292 |
|
| 293 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 294 |
recalcEquity();
|
| 295 |
-
|
|
|
|
| 296 |
}
|
| 297 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 298 |
function resetLocal(){
|
| 299 |
state.cash = INITIAL_CASH;
|
| 300 |
state.shares = 0;
|
|
|
|
| 270 |
}
|
| 271 |
}
|
| 272 |
|
| 273 |
+
function placeOrder(side, qty){
|
| 274 |
+
qty = Math.floor(Number(qty));
|
| 275 |
+
if (!Number.isFinite(qty) || qty <= 0) return;
|
| 276 |
+
if (!Number.isFinite(state.price) || state.price <= 0) return;
|
| 277 |
+
|
| 278 |
+
const tradeShares = (side === "BUY") ? qty : -qty; // SELL is negative shares
|
| 279 |
+
const px = state.price;
|
| 280 |
+
|
| 281 |
+
// Cash flow: buying spends cash, selling receives cash
|
| 282 |
+
// cashDelta = - (tradeShares * price) - commission
|
| 283 |
+
// (if tradeShares is negative => -(-qty*px) = +qty*px)
|
| 284 |
+
const cashDelta = -(tradeShares * px) - COMMISSION;
|
| 285 |
+
|
| 286 |
+
// Optional: simple leverage guard (to avoid infinite short)
|
| 287 |
+
// e.g. require equity stays above 0 after the trade
|
| 288 |
+
// We'll compute after updating state, and revert if violates.
|
| 289 |
+
const old = { cash: state.cash, shares: state.shares, avgCost: state.avgCost };
|
| 290 |
+
|
| 291 |
+
// Update cash
|
| 292 |
+
state.cash += cashDelta;
|
| 293 |
+
|
| 294 |
+
// Update position + avgCost (handles long<->flat<->short)
|
| 295 |
+
const prevShares = state.shares;
|
| 296 |
+
const newShares = prevShares + tradeShares;
|
| 297 |
+
|
| 298 |
+
// Helper: same direction means both >=0 or both <=0 (excluding 0)
|
| 299 |
+
const sameDir =
|
| 300 |
+
(prevShares > 0 && newShares > 0) ||
|
| 301 |
+
(prevShares < 0 && newShares < 0);
|
| 302 |
+
|
| 303 |
+
if (newShares === 0) {
|
| 304 |
+
state.shares = 0;
|
| 305 |
+
state.avgCost = 0;
|
| 306 |
+
} else if (prevShares === 0) {
|
| 307 |
+
// Opening a new position (long or short)
|
| 308 |
+
state.shares = newShares;
|
| 309 |
+
state.avgCost = px;
|
| 310 |
+
} else if (sameDir) {
|
| 311 |
+
// Increasing position in the same direction => weighted average price
|
| 312 |
+
// weights are absolute sizes
|
| 313 |
+
const totalAbs = Math.abs(prevShares) + Math.abs(tradeShares);
|
| 314 |
+
const avg = (Math.abs(prevShares) * state.avgCost + Math.abs(tradeShares) * px) / totalAbs;
|
| 315 |
+
state.shares = newShares;
|
| 316 |
+
state.avgCost = avg;
|
| 317 |
+
} else {
|
| 318 |
+
// Reducing/closing/reversing: avgCost stays the same if partially reduced;
|
| 319 |
+
// if reversed beyond zero, new avgCost becomes entry price of the remainder.
|
| 320 |
+
state.shares = newShares;
|
| 321 |
+
|
| 322 |
+
const reducedToZeroOrBeyond =
|
| 323 |
+
(prevShares > 0 && newShares < 0) || (prevShares < 0 && newShares > 0);
|
| 324 |
+
|
| 325 |
+
if (reducedToZeroOrBeyond) {
|
| 326 |
+
// Position flipped direction; remaining shares have new entry at px
|
| 327 |
+
state.avgCost = px;
|
| 328 |
} else {
|
| 329 |
+
// Still same original direction but smaller size; keep avgCost
|
| 330 |
+
// (avgCost unchanged)
|
|
|
|
|
|
|
| 331 |
}
|
| 332 |
+
}
|
| 333 |
+
|
| 334 |
+
// Record order
|
| 335 |
+
state.orders.push({ side, qty, price: px, day: state.day, ts: Date.now() });
|
| 336 |
+
|
| 337 |
+
// Recalc equity and (optional) enforce margin rule
|
| 338 |
+
recalcEquity();
|
| 339 |
|
| 340 |
+
// Simple margin guard (optional but strongly recommended):
|
| 341 |
+
// disallow trades that make equity negative
|
| 342 |
+
if (state.equity <= 0) {
|
| 343 |
+
// revert
|
| 344 |
+
state.cash = old.cash;
|
| 345 |
+
state.shares = old.shares;
|
| 346 |
+
state.avgCost = old.avgCost;
|
| 347 |
recalcEquity();
|
| 348 |
+
state.orders.pop();
|
| 349 |
+
return;
|
| 350 |
}
|
| 351 |
|
| 352 |
+
render();
|
| 353 |
+
}
|
| 354 |
+
|
| 355 |
+
|
| 356 |
function resetLocal(){
|
| 357 |
state.cash = INITIAL_CASH;
|
| 358 |
state.shares = 0;
|