Show description
OPEX_COMMAND // ARCHITECT_BUILD
OPEX_COMMAND // ARCHITECT_BUILD
Black-Scholes // Solver v.0.9.1
Spot Price ($) 100
Strike Price ($) 100
Volatility (IV %) 20%
Time to Expiry (Days) 30
Interest Rate (%) 5%
VISUALIZATION:
X-Axis: Spot Price
Y-Axis: Time to Expiry
Z-Axis (Height/Color): Option Premium
SURFACE_RENDERING_ENGINE::ACTIVE
ISO_PROJECTION_MATRIX
The Greeks (Sensitivity)
DELTA 0.00
GAMMA 0.00
THETA 0.00
VEGA 0.00
RHO 0.00
Option Price
$0.00
L2 Order Depth
OPEX_COMMAND // ARCHITECT_BUILD
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>OPEX_COMMAND // ARCHITECT_BUILD</title>
<style>
:root {
--bg-core: #050505;
--bg-panel: #0a0a0a;
--border-subtle: #1a1a1a;
--border-active: #333;
--accent-primary: #ff003c; /* Cyber Red */
--accent-dim: #5c0016;
--text-main: #e5e5e5;
--text-muted: #666;
--font-mono: 'JetBrains Mono', 'Fira Code', Consolas, monospace;
}
* { box-sizing: border-box; margin: 0; padding: 0; user-select: none; }
body {
background-color: var(--bg-core);
color: var(--text-main);
font-family: var(--font-mono);
height: 100vh;
overflow: hidden;
display: flex;
flex-direction: column;
}
/* --- UI FRAMEWORK --- */
header {
height: 50px;
border-bottom: 1px solid var(--border-subtle);
display: flex;
align-items: center;
padding: 0 1.5rem;
justify-content: space-between;
background: linear-gradient(90deg, #000 0%, #111 100%);
}
h1 {
font-size: 0.9rem;
letter-spacing: 2px;
color: var(--accent-primary);
text-transform: uppercase;
}
.status-light {
width: 8px;
height: 8px;
background-color: var(--accent-primary);
border-radius: 50%;
box-shadow: 0 0 10px var(--accent-primary);
animation: pulse 2s infinite;
}
main {
flex: 1;
display: grid;
grid-template-columns: 300px 1fr 250px;
height: calc(100vh - 50px);
}
/* --- CONTROL PANEL (LEFT) --- */
.panel {
border-right: 1px solid var(--border-subtle);
background: var(--bg-panel);
display: flex;
flex-direction: column;
padding: 1.5rem;
gap: 2rem;
overflow-y: auto;
}
.control-group {
display: flex;
flex-direction: column;
gap: 0.5rem;
}
label {
font-size: 0.7rem;
color: var(--text-muted);
text-transform: uppercase;
letter-spacing: 1px;
display: flex;
justify-content: space-between;
}
input[type="range"] {
-webkit-appearance: none;
width: 100%;
height: 4px;
background: var(--border-active);
outline: none;
cursor: ns-resize;
}
input[type="range"]::-webkit-slider-thumb {
-webkit-appearance: none;
width: 12px;
height: 12px;
background: var(--accent-primary);
cursor: pointer;
box-shadow: 0 0 10px var(--accent-dim);
}
.value-display {
color: var(--accent-primary);
}
/* --- VISUALIZATION (CENTER) --- */
.viewport {
position: relative;
background: radial-gradient(circle at center, #111 0%, #000 100%);
overflow: hidden;
display: flex;
justify-content: center;
align-items: center;
}
#surfaceCanvas {
width: 100%;
height: 100%;
}
.overlay-info {
position: absolute;
top: 20px;
left: 20px;
font-size: 0.8rem;
color: var(--text-muted);
pointer-events: none;
}
/* --- ORDER BOOK / GREEKS (RIGHT) --- */
.sidebar {
border-left: 1px solid var(--border-subtle);
background: var(--bg-panel);
display: flex;
flex-direction: column;
}
.module {
flex: 1;
border-bottom: 1px solid var(--border-subtle);
padding: 1rem;
display: flex;
flex-direction: column;
}
.module h3 {
font-size: 0.7rem;
color: var(--text-muted);
margin-bottom: 1rem;
text-transform: uppercase;
}
.greek-row {
display: flex;
justify-content: space-between;
margin-bottom: 0.8rem;
font-size: 0.85rem;
border-bottom: 1px dashed #222;
padding-bottom: 4px;
}
.greek-val { color: #fff; }
#orderBookCanvas {
width: 100%;
height: 200px;
margin-top: auto;
}
/* Animations */
@keyframes pulse {
0% { opacity: 0.5; box-shadow: 0 0 0px var(--accent-primary); }
50% { opacity: 1; box-shadow: 0 0 15px var(--accent-primary); }
100% { opacity: 0.5; box-shadow: 0 0 0px var(--accent-primary); }
}
/* Responsive */
@media (max-width: 900px) {
main { grid-template-columns: 1fr; grid-template-rows: auto 400px auto; overflow-y: scroll; }
.panel { border-right: none; border-bottom: 1px solid var(--border-subtle); }
.viewport { height: 400px; }
}
</style>
</head>
<body>
<header>
<h1>Black-Scholes // Solver <span style="font-size:0.6em; opacity:0.5;">v.0.9.1</span></h1>
<div class="status-light"></div>
</header>
<main>
<!-- CONTROLS -->
<div class="panel">
<div class="control-group">
<label>Spot Price ($) <span class="value-display" id="val-spot">100</span></label>
<input type="range" id="spot" min="50" max="150" value="100">
</div>
<div class="control-group">
<label>Strike Price ($) <span class="value-display" id="val-strike">100</span></label>
<input type="range" id="strike" min="50" max="150" value="100">
</div>
<div class="control-group">
<label>Volatility (IV %) <span class="value-display" id="val-vol">20%</span></label>
<input type="range" id="vol" min="1" max="100" value="20">
</div>
<div class="control-group">
<label>Time to Expiry (Days) <span class="value-display" id="val-time">30</span></label>
<input type="range" id="time" min="1" max="365" value="30">
</div>
<div class="control-group">
<label>Interest Rate (%) <span class="value-display" id="val-rate">5%</span></label>
<input type="range" id="rate" min="0" max="20" step="0.5" value="5">
</div>
<div style="margin-top: 2rem; border-top: 1px solid #222; padding-top: 1rem;">
<p style="font-size: 0.7rem; color: #444; line-height: 1.5;">
VISUALIZATION:<br>
X-Axis: Spot Price<br>
Y-Axis: Time to Expiry<br>
Z-Axis (Height/Color): Option Premium
</p>
</div>
</div>
<!-- 3D HEATMAP -->
<div class="viewport">
<div class="overlay-info">
SURFACE_RENDERING_ENGINE::ACTIVE<br>
ISO_PROJECTION_MATRIX
</div>
<canvas id="surfaceCanvas"></canvas>
</div>
<!-- ANALYTICS SIDEBAR -->
<div class="sidebar">
<div class="module">
<h3>The Greeks (Sensitivity)</h3>
<div class="greek-row"><span>DELTA</span> <span class="greek-val" id="g-delta">0.00</span></div>
<div class="greek-row"><span>GAMMA</span> <span class="greek-val" id="g-gamma">0.00</span></div>
<div class="greek-row"><span>THETA</span> <span class="greek-val" id="g-theta">0.00</span></div>
<div class="greek-row"><span>VEGA</span> <span class="greek-val" id="g-vega">0.00</span></div>
<div class="greek-row"><span>RHO</span> <span class="greek-val" id="g-rho">0.00</span></div>
<h3 style="margin-top: 2rem;">Option Price</h3>
<div style="font-size: 1.5rem; color: var(--accent-primary); text-align: right;" id="opt-price">$0.00</div>
</div>
<div class="module" style="padding:0; flex:1; display:flex; flex-direction:column;">
<h3 style="padding: 1rem 1rem 0 1rem;">L2 Order Depth</h3>
<canvas id="orderBookCanvas"></canvas>
</div>
</div>
</main>
<script>
// --- BLACK SCHOLES MATH ENGINE ---
// Standard Normal CDF approximation
function N(x) {
var a1 = 0.254829592;
var a2 = -0.284496736;
var a3 = 1.421413741;
var a4 = -1.453152027;
var a5 = 1.061405429;
var p = 0.3275911;
// Save the sign of x
var sign = 1;
if (x < 0) sign = -1;
x = Math.abs(x)/Math.sqrt(2.0);
// A&S formula 7.1.26
var t = 1.0/(1.0 + p*x);
var y = 1.0 - (((((a5*t + a4)*t) + a3)*t + a2)*t + a1)*t*Math.exp(-x*x);
return 0.5*(1.0 + sign*y);
}
// Standard Normal PDF
function N_prime(x) {
return Math.exp(-0.5 * x * x) / Math.sqrt(2 * Math.PI);
}
function calculateBlackScholes(S, K, T, r, v, type="call") {
const d1 = (Math.log(S / K) + (r + v * v / 2) * T) / (v * Math.sqrt(T));
const d2 = d1 - v * Math.sqrt(T);
let price = 0;
let delta = 0;
let theta = 0;
if (type === "call") {
price = S * N(d1) - K * Math.exp(-r * T) * N(d2);
delta = N(d1);
theta = (- (S * N_prime(d1) * v) / (2 * Math.sqrt(T)) - r * K * Math.exp(-r * T) * N(d2)) / 365;
} else {
price = K * Math.exp(-r * T) * N(-d2) - S * N(-d1);
delta = N(d1) - 1;
theta = (- (S * N_prime(d1) * v) / (2 * Math.sqrt(T)) + r * K * Math.exp(-r * T) * N(-d2)) / 365;
}
const gamma = N_prime(d1) / (S * v * Math.sqrt(T));
const vega = S * Math.sqrt(T) * N_prime(d1) / 100; // Divide by 100 for percentage move
const rho = K * T * Math.exp(-r * T) * N(d2) / 100;
return { price, delta, gamma, theta, vega, rho };
}
// --- STATE MANAGEMENT ---
const inputs = {
spot: document.getElementById('spot'),
strike: document.getElementById('strike'),
vol: document.getElementById('vol'),
time: document.getElementById('time'),
rate: document.getElementById('rate')
};
const displays = {
spot: document.getElementById('val-spot'),
strike: document.getElementById('val-strike'),
vol: document.getElementById('val-vol'),
time: document.getElementById('val-time'),
rate: document.getElementById('val-rate'),
price: document.getElementById('opt-price'),
delta: document.getElementById('g-delta'),
gamma: document.getElementById('g-gamma'),
theta: document.getElementById('g-theta'),
vega: document.getElementById('g-vega'),
rho: document.getElementById('g-rho')
};
// --- 3D RENDERER (ISOMETRIC WIREFRAME/MESH) ---
const cvs = document.getElementById('surfaceCanvas');
const ctx = cvs.getContext('2d');
let width, height;
function resize() {
width = cvs.parentElement.clientWidth;
height = cvs.parentElement.clientHeight;
cvs.width = width;
cvs.height = height;
}
window.addEventListener('resize', resize);
resize();
// Coordinate projection (3D -> 2D)
function project(x, y, z) {
// Isometric view
const scale = 1.5;
const isoX = (x - y) * Math.cos(0.523); // 30 degrees
const isoY = (x + y) * Math.sin(0.523) - z;
return {
x: width / 2 + isoX * scale,
y: height / 1.5 + isoY * scale // Shift down slightly
};
}
function drawSurface() {
ctx.clearRect(0, 0, width, height);
const S_curr = parseFloat(inputs.spot.value);
const K = parseFloat(inputs.strike.value);
const r = parseFloat(inputs.rate.value) / 100;
const v = parseFloat(inputs.vol.value) / 100;
const T_days = parseFloat(inputs.time.value);
// Grid Definition
const rows = 15; // Time steps
const cols = 20; // Price steps
const spotRange = 100; // +/- range around strike
const grid = [];
// Generate Grid Data
for(let i = 0; i <= rows; i++) {
const t = 0.01 + (i / rows) * (365/365); // Time from 0 to 1 year (approx)
const row = [];
for(let j = 0; j <= cols; j++) {
const s = (K - spotRange/2) + (j / cols) * spotRange; // Spot prices around strike
const data = calculateBlackScholes(s, K, t, r, v, 'call');
row.push({
x: (j - cols/2) * 15, // Screen space X spacing
y: (i - rows/2) * 15, // Screen space Y spacing
z: data.price * 3, // Height multiplier
price: data.price
});
}
grid.push(row);
}
// Draw Polygons
for(let i = 0; i < rows; i++) {
for(let j = 0; j < cols; j++) {
const p1 = grid[i][j];
const p2 = grid[i][j+1];
const p3 = grid[i+1][j+1];
const p4 = grid[i+1][j];
const pro1 = project(p1.x, p1.y, p1.z);
const pro2 = project(p2.x, p2.y, p2.z);
const pro3 = project(p3.x, p3.y, p3.z);
const pro4 = project(p4.x, p4.y, p4.z);
// Color based on height (price)
// Red gradient: Dark red (low price) -> Bright Red (high price)
const intensity = Math.min(255, Math.floor((p1.price / 80) * 255));
ctx.fillStyle = `rgba(${intensity}, 0, ${intensity/4}, 0.6)`;
ctx.strokeStyle = `rgba(255, 50, 50, 0.2)`;
ctx.beginPath();
ctx.moveTo(pro1.x, pro1.y);
ctx.lineTo(pro2.x, pro2.y);
ctx.lineTo(pro3.x, pro3.y);
ctx.lineTo(pro4.x, pro4.y);
ctx.closePath();
ctx.fill();
ctx.stroke();
}
}
// Draw "Current Position" Marker
// Locate approximate position on grid
// This is just a visual approximation for the user's current settings
const currentData = calculateBlackScholes(S_curr, K, T_days/365, r, v, 'call');
// We draw a floating sphere roughly where the user is
// Re-calculating specific projection for the user's specific S and T relative to grid center
// X-coord logic: (S - K) scaled
// Y-coord logic: (T - 0.5) scaled
// This is tricky to align perfectly with the grid loop, so we stick to updating the numeric display primarily.
updateGreeks(currentData);
}
function updateGreeks(data) {
displays.price.innerText = "$" + data.price.toFixed(2);
displays.delta.innerText = data.delta.toFixed(3);
displays.gamma.innerText = data.gamma.toFixed(3);
displays.theta.innerText = data.theta.toFixed(3);
displays.vega.innerText = data.vega.toFixed(3);
displays.rho.innerText = data.rho.toFixed(3);
}
// --- ORDER BOOK VISUALIZER ---
const bookCvs = document.getElementById('orderBookCanvas');
const bookCtx = bookCvs.getContext('2d');
let bookW, bookH;
function resizeBook() {
bookW = bookCvs.parentElement.clientWidth;
bookH = 200; // Fixed height
bookCvs.width = bookW;
bookCvs.height = bookH;
}
window.addEventListener('resize', resizeBook);
resizeBook();
// Generate fake order book data
let asks = [];
let bids = [];
function generateBook() {
asks = [];
bids = [];
let val = 0;
for(let i=0; i<50; i++) {
val += Math.random() * 10;
bids.push(val); // Accumulating volume
}
val = 0;
for(let i=0; i<50; i++) {
val += Math.random() * 10;
asks.push(val);
}
}
generateBook();
function drawBook() {
bookCtx.clearRect(0,0,bookW, bookH);
const mid = bookW / 2;
const maxVol = 300; // Scale factor
// Draw Bids (Green/Cyan - but staying in Red/Grey theme: use Dark Grey/White)
// Actually, usually Bids=Green Asks=Red.
// For this theme: Bids = White/Grey, Asks = Red.
bookCtx.fillStyle = "rgba(255, 255, 255, 0.1)";
bookCtx.beginPath();
bookCtx.moveTo(mid, bookH);
for(let i=0; i<bids.length; i++) {
const x = mid - (i * (mid/50));
const y = bookH - (bids[i] / maxVol) * bookH;
bookCtx.lineTo(x, y);
}
bookCtx.lineTo(0, bookH);
bookCtx.fill();
// Draw Asks (Red)
bookCtx.fillStyle = "rgba(255, 0, 60, 0.2)";
bookCtx.beginPath();
bookCtx.moveTo(mid, bookH);
for(let i=0; i<asks.length; i++) {
const x = mid + (i * (mid/50));
const y = bookH - (asks[i] / maxVol) * bookH;
bookCtx.lineTo(x, y);
}
bookCtx.lineTo(bookW, bookH);
bookCtx.fill();
// Midpoint line
bookCtx.strokeStyle = "#444";
bookCtx.beginPath();
bookCtx.moveTo(mid, 0);
bookCtx.lineTo(mid, bookH);
bookCtx.stroke();
}
// --- ANIMATION LOOP ---
function animate() {
drawSurface();
// Jitter the order book occasionally
if(Math.random() > 0.9) generateBook();
drawBook();
requestAnimationFrame(animate);
}
// --- EVENT LISTENERS ---
Object.keys(inputs).forEach(key => {
inputs[key].addEventListener('input', (e) => {
// Update display text
let val = e.target.value;
if(key === 'vol' || key === 'rate') val += '%';
if(key === 'time') val += ' Days';
displays[key].innerText = val;
});
});
animate();
</script>
</body>
</html>