Skip to content
LAM
Read Home Blog
Make Projects HTML Tools Games
Touch grass Notes Resume Links
Home Blog HTML Projects
Tools Games Notes Resume Links
Back OPEX_COMMAND // ARCHITECT_BUILD Finance
Download Open
Show description 577 chars · Finance

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

20,177 bytes · HTML source
<!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>