Skip to main content
Glama
jjsteffen23

CME Prediction Markets MCP Server

by jjsteffen23
trading_data.html43.8 kB
{% extends "base.html" %} {% block title %}Trading Data - CME MCP Server{% endblock %} {% block content %} <div class="row"> <div class="col-lg-4"> <!-- Query Panel --> <div class="card"> <div class="card-header"> <h5 class="mb-0"> <i class="fas fa-chart-candlestick me-2"></i>Trading Data Query </h5> </div> <div class="card-body"> <form id="trading-form"> <div class="mb-3"> <label for="contract-symbol" class="form-label">Contract Symbol:</label> <input type="text" class="form-control" id="contract-symbol" placeholder="e.g., BTC_95000_YES" required> </div> <div class="mb-3"> <label for="start-time" class="form-label">Start Time:</label> <input type="datetime-local" class="form-control" id="start-time" required> </div> <div class="mb-3"> <label for="end-time" class="form-label">End Time:</label> <input type="datetime-local" class="form-control" id="end-time" required> </div> <div class="mb-3"> <label for="aggregation" class="form-label">Aggregation:</label> <select class="form-select" id="aggregation"> <option value="raw">Raw Data</option> <option value="minute">1 Minute</option> <option value="hour">1 Hour</option> <option value="day">1 Day</option> </select> </div> <button type="submit" class="btn btn-primary w-100"> <i class="fas fa-search me-2"></i>Query Data </button> </form> <!-- Quick Time Ranges --> <hr> <h6>Quick Ranges:</h6> <div class="d-grid gap-2"> <button class="btn btn-outline-secondary btn-sm" onclick="setTimeRange(1)"> Last 24 Hours </button> <button class="btn btn-outline-secondary btn-sm" onclick="setTimeRange(7)"> Last 7 Days </button> <button class="btn btn-outline-secondary btn-sm" onclick="setTimeRange(30)"> Last 30 Days </button> </div> </div> </div> </div> <div class="col-lg-8"> <!-- Results Panel --> <div class="card"> <div class="card-header"> <h5 class="mb-0"> <i class="fas fa-chart-line me-2"></i>Trading Results </h5> </div> <div class="card-body"> <div id="trading-results"> <div class="text-center text-muted py-5"> <i class="fas fa-chart-candlestick fa-3x mb-3"></i> <p>Query trading data to view results</p> </div> </div> </div> </div> </div> </div> <!-- TastyTrade Integration --> <div class="row mt-4"> <div class="col-12"> <div class="card border-info"> <div class="card-header bg-info text-white"> <h5 class="mb-0"> <i class="fas fa-broadcast-tower me-2"></i>TastyTrade Live Market Data </h5> </div> <div class="card-body" id="tastytradeStatus"> <div class="row align-items-center"> <div class="col-md-6"> <h6>Connection Status: <span id="connectionStatus" class="text-muted">Not Connected</span></h6> <div id="accountInfo" style="display: none;"> <small class="text-muted">Account: <span id="accountName"></span></small> </div> </div> <div class="col-md-6 text-end"> <button id="connectBtn" class="btn btn-success me-2" onclick="connectTastyTrade()"> <i class="fas fa-plug me-2"></i>Connect TastyTrade </button> <button id="disconnectBtn" class="btn btn-outline-danger" onclick="disconnectTastyTrade()" style="display: none;"> <i class="fas fa-times me-2"></i>Disconnect </button> </div> </div> <div class="mt-3"> <small class="text-muted"> <i class="fas fa-info-circle me-1"></i> Connect to TastyTrade to access live market data and real-time quotes for enhanced analysis. </small> </div> </div> </div> </div> </div> <!-- CME Data Fetching --> <div class="row mt-4"> <div class="col-12"> <div class="card border-primary"> <div class="card-header bg-primary text-white"> <h5 class="mb-0"> <i class="fas fa-download me-2"></i>Fetch CME Data </h5> </div> <div class="card-body" id="cmeDataStatus"> <div class="row align-items-center"> <div class="col-md-8"> <h6>Status: <span id="cmeStatus" class="text-muted">Ready</span></h6> <div id="cmeStats" class="mt-2"> <small class="text-muted">Database stats loading...</small> </div> <div id="cmeProgress" class="mt-3" style="display: none;"> <div class="progress"> <div class="progress-bar progress-bar-striped progress-bar-animated" role="progressbar" style="width: 100%"> Processing... </div> </div> </div> </div> <div class="col-md-4 text-end"> <div class="btn-group me-2" role="group"> <button id="fetchCmeBtn" class="btn btn-primary" onclick="fetchCMEData(false, true)"> <i class="fas fa-download me-2"></i>Fetch with API </button> <button type="button" class="btn btn-outline-primary dropdown-toggle dropdown-toggle-split" data-bs-toggle="dropdown"> <span class="visually-hidden">Toggle Dropdown</span> </button> <ul class="dropdown-menu"> <li><a class="dropdown-item" href="#" onclick="fetchCMEData(false, true)"> <i class="fas fa-rocket me-2"></i>Enhanced API + CSV </a></li> <li><a class="dropdown-item" href="#" onclick="fetchCMEData(false, false)"> <i class="fas fa-file-csv me-2"></i>Legacy CSV Only </a></li> <li><a class="dropdown-item" href="#" onclick="fetchCMEData(true, true)"> <i class="fas fa-sync-alt me-2"></i>Force Refresh (API) </a></li> <li><hr class="dropdown-divider"></li> <li><a class="dropdown-item" href="#" onclick="previewAPIData()"> <i class="fas fa-eye me-2"></i>Preview API Data </a></li> </ul> </div> <div class="btn-group" role="group"> <button type="button" class="btn btn-outline-secondary btn-sm" onclick="refreshCMEStatus()"> <i class="fas fa-sync-alt"></i> </button> <button type="button" class="btn btn-outline-secondary btn-sm" onclick="showSampleData()"> <i class="fas fa-table"></i> </button> </div> </div> </div> <div class="mt-3"> <small class="text-muted"> <i class="fas fa-info-circle me-1"></i> <strong>Enhanced:</strong> Uses CME Reference Data API for real-time contract metadata + CSV for trade history. Provides event contract classification, fixed payouts, and tradeable product links. </small> </div> <div id="cmeLastFetch" class="mt-2" style="display: none;"> <small class="text-success"> <i class="fas fa-check-circle me-1"></i> <span id="cmeLastFetchTime"></span> </small> </div> </div> </div> </div> </div> <!-- CME Sample Data Modal --> <div class="modal fade" id="sampleDataModal" tabindex="-1"> <div class="modal-dialog modal-lg"> <div class="modal-content"> <div class="modal-header"> <h5 class="modal-title"> <i class="fas fa-table me-2"></i>Sample CME Data </h5> <button type="button" class="btn-close" data-bs-dismiss="modal"></button> </div> <div class="modal-body" id="sampleDataContent"> <div class="text-center"> <div class="spinner-border text-primary" role="status"> <span class="visually-hidden">Loading...</span> </div> </div> </div> </div> </div> </div> <!-- Data Visualization --> <div class="row mt-4" id="chart-section" style="display: none;"> <div class="col-12"> <div class="card"> <div class="card-header"> <h5 class="mb-0"> <i class="fas fa-chart-area me-2"></i>Price Visualization </h5> </div> <div class="card-body"> <canvas id="price-chart" width="400" height="100"></canvas> </div> </div> </div> </div> <!-- Trade Details --> <div class="row mt-4" id="trades-section" style="display: none;"> <div class="col-12"> <div class="card"> <div class="card-header"> <h5 class="mb-0"> <i class="fas fa-table me-2"></i>Trade Details </h5> </div> <div class="card-body"> <div id="trades-table"></div> </div> </div> </div> </div> {% endblock %} {% block scripts %} <script src="https://cdn.jsdelivr.net/npm/chart.js"></script> <script> let priceChart = null; $(document).ready(function() { // Set default time range to last 24 hours setTimeRange(1); // Handle URL parameters const urlParams = new URLSearchParams(window.location.search); const contractParam = urlParams.get('contract'); if (contractParam) { $('#contract-symbol').val(contractParam); } $('#trading-form').on('submit', async function(e) { e.preventDefault(); await queryTradingData(); }); }); function setTimeRange(days) { const end = new Date(); const start = new Date(end.getTime() - (days * 24 * 60 * 60 * 1000)); $('#start-time').val(formatDateForInput(start)); $('#end-time').val(formatDateForInput(end)); } function formatDateForInput(date) { const year = date.getFullYear(); const month = String(date.getMonth() + 1).padStart(2, '0'); const day = String(date.getDate()).padStart(2, '0'); const hours = String(date.getHours()).padStart(2, '0'); const minutes = String(date.getMinutes()).padStart(2, '0'); return `${year}-${month}-${day}T${hours}:${minutes}`; } async function queryTradingData() { const symbol = $('#contract-symbol').val().trim(); const startTime = $('#start-time').val(); const endTime = $('#end-time').val(); const aggregation = $('#aggregation').val(); if (!symbol || !startTime || !endTime) { alert('Please fill in all required fields.'); return; } const resultsDiv = document.getElementById('trading-results'); showLoading(resultsDiv); try { const response = await mcpClient.callTool('query_trading_data', { contract_symbol: symbol, start_time: new Date(startTime).toISOString(), end_time: new Date(endTime).toISOString(), aggregation: aggregation }); if (response.success) { displayTradingResults(response.result); if (response.result.trades.length > 0) { createPriceChart(response.result.trades); displayTradesTable(response.result.trades); } } else { showError(resultsDiv, response.error || 'Query failed'); $('#chart-section, #trades-section').hide(); } } catch (error) { showError(resultsDiv, 'Network error: ' + error.message); $('#chart-section, #trades-section').hide(); } } function displayTradingResults(data) { const summary = data.summary; let html = ` <div class="row"> <div class="col-md-8"> <h5>${data.contract_symbol}</h5> <p class="text-muted">${data.contract_description || 'Contract details'}</p> <div class="mb-3"> <strong>Query Period:</strong> ${new Date(data.start_time).toLocaleString()} - ${new Date(data.end_time).toLocaleString()} </div> ${summary.message ? ` <div class="alert alert-info mb-3"> <i class="fas fa-info-circle me-2"></i>${summary.message} </div> ` : ''} </div> <div class="col-md-4"> <div class="card bg-light"> <div class="card-body"> <h6 class="card-title">Summary Statistics</h6> <div class="row mb-2"> <div class="col-6"><small>Total Trades:</small></div> <div class="col-6 text-end"><strong>${summary.total_trades || summary.count || 0}</strong></div> </div> ${summary.open !== null && summary.open !== undefined ? ` <div class="row mb-2"> <div class="col-6"><small>Open:</small></div> <div class="col-6 text-end">${summary.open.toFixed ? summary.open.toFixed(4) : summary.open}</div> </div> ` : ''} ${summary.high !== null && summary.high !== undefined ? ` <div class="row mb-2"> <div class="col-6"><small>High:</small></div> <div class="col-6 text-end text-success">${summary.high.toFixed ? summary.high.toFixed(4) : summary.high}</div> </div> ` : ''} ${summary.low !== null && summary.low !== undefined ? ` <div class="row mb-2"> <div class="col-6"><small>Low:</small></div> <div class="col-6 text-end text-danger">${summary.low.toFixed ? summary.low.toFixed(4) : summary.low}</div> </div> ` : ''} ${summary.close !== null && summary.close !== undefined ? ` <div class="row mb-2"> <div class="col-6"><small>Close:</small></div> <div class="col-6 text-end">${summary.close.toFixed ? summary.close.toFixed(4) : summary.close}</div> </div> ` : ''} ${summary.total_volume !== null && summary.total_volume !== undefined ? ` <div class="row mb-2"> <div class="col-6"><small>Volume:</small></div> <div class="col-6 text-end">${summary.total_volume}</div> </div> ` : ''} ${summary.vwap !== null && summary.vwap !== undefined ? ` <div class="row"> <div class="col-6"><small>VWAP:</small></div> <div class="col-6 text-end">${summary.vwap.toFixed(4)}</div> </div> ` : ''} </div> </div> </div> </div> `; document.getElementById('trading-results').innerHTML = html; } function createPriceChart(trades) { const ctx = document.getElementById('price-chart').getContext('2d'); // Destroy existing chart if (priceChart) { priceChart.destroy(); } const labels = trades.map(trade => new Date(trade.timestamp).toLocaleString()); const prices = trades.map(trade => trade.price); priceChart = new Chart(ctx, { type: 'line', data: { labels: labels, datasets: [{ label: 'Price', data: prices, borderColor: 'rgb(75, 192, 192)', backgroundColor: 'rgba(75, 192, 192, 0.2)', tension: 0.1, fill: true }] }, options: { responsive: true, plugins: { title: { display: true, text: 'Price Movement Over Time' } }, scales: { y: { beginAtZero: false, title: { display: true, text: 'Price' } }, x: { title: { display: true, text: 'Time' } } }, interaction: { intersect: false, mode: 'index' } } }); $('#chart-section').show(); } function displayTradesTable(trades) { let html = ` <div class="table-responsive"> <table class="table table-striped table-hover"> <thead> <tr> <th>Timestamp</th> <th>Price</th> <th>Volume</th> <th>Trade ID</th> </tr> </thead> <tbody> `; trades.slice(0, 100).forEach(trade => { html += ` <tr> <td>${new Date(trade.timestamp).toLocaleString()}</td> <td class="fw-bold">${trade.price}</td> <td>${trade.volume}</td> <td><small class="text-muted">${trade.trade_id}</small></td> </tr> `; }); html += '</tbody></table>'; if (trades.length > 100) { html += ` <div class="alert alert-info"> <i class="fas fa-info-circle me-2"></i> Showing first 100 of ${trades.length} trades. Use aggregation for larger datasets. </div> `; } html += '</div>'; document.getElementById('trades-table').innerHTML = html; $('#trades-section').show(); } // TastyTrade OAuth2 Integration let tastytradeSession = null; // Check URL parameters for TastyTrade connection status window.addEventListener('DOMContentLoaded', function() { const urlParams = new URLSearchParams(window.location.search); const sessionId = urlParams.get('tastytrade_session'); const connected = urlParams.get('connected'); if (sessionId && connected === 'true') { tastytradeSession = sessionId; updateTastyTradeStatus(true); loadTastyTradeData(); // Clean URL const cleanUrl = window.location.pathname; window.history.replaceState({}, document.title, cleanUrl); } }); async function connectTastyTrade() { try { const connectBtn = document.getElementById('connectBtn'); if (!connectBtn) { console.error('Connect button not found'); return; } if (typeof showLoading === 'function') { showLoading(connectBtn); } else { connectBtn.innerHTML = '<i class="fas fa-spinner fa-spin me-2"></i>Connecting...'; } // Initiate OAuth flow const response = await fetch('/api/tastytrade/auth'); if (!response.ok) { throw new Error(`HTTP ${response.status}: ${response.statusText}`); } const contentType = response.headers.get('content-type'); if (!contentType || !contentType.includes('application/json')) { throw new Error('Server returned non-JSON response'); } const data = await response.json(); if (data.auth_url) { // Redirect to TastyTrade OAuth window.location.href = data.auth_url; } else { throw new Error(data.message || 'Failed to initiate OAuth flow'); } } catch (error) { console.error('TastyTrade connection error:', error); const connectBtn = document.getElementById('connectBtn'); if (connectBtn) { connectBtn.innerHTML = '<i class="fas fa-plug me-2"></i>Connect TastyTrade'; } // Show user-friendly error message const errorMsg = error.message.includes('HTTP') ? 'Server error - please try again later' : 'Failed to connect to TastyTrade. Please check your configuration.'; showCMENotification(errorMsg, 'error'); } } async function disconnectTastyTrade() { try { if (tastytradeSession) { await fetch('/api/tastytrade/disconnect', { method: 'POST', headers: {'Content-Type': 'application/json'}, body: JSON.stringify({session_id: tastytradeSession}) }); } tastytradeSession = null; updateTastyTradeStatus(false); } catch (error) { console.error('Disconnect error:', error); } } function updateTastyTradeStatus(connected) { const connectBtn = document.getElementById('connectBtn'); const disconnectBtn = document.getElementById('disconnectBtn'); const connectionStatus = document.getElementById('connectionStatus'); const accountInfo = document.getElementById('accountInfo'); if (connected) { connectBtn.style.display = 'none'; disconnectBtn.style.display = 'inline-block'; connectionStatus.textContent = 'Connected'; connectionStatus.className = 'text-success'; // Load account info loadAccountInfo(); } else { connectBtn.style.display = 'inline-block'; connectBtn.innerHTML = '<i class="fas fa-plug me-2"></i>Connect TastyTrade'; disconnectBtn.style.display = 'none'; connectionStatus.textContent = 'Not Connected'; connectionStatus.className = 'text-muted'; accountInfo.style.display = 'none'; } } async function loadAccountInfo() { try { const response = await fetch(`/api/tastytrade/account?session_id=${tastytradeSession}`); const data = await response.json(); if (data.status === 'success' && data.account) { const accountName = data.account.data?.[0]?.account?.['account-number'] || 'Connected Account'; document.getElementById('accountName').textContent = accountName; document.getElementById('accountInfo').style.display = 'block'; } } catch (error) { console.error('Failed to load account info:', error); } } async function loadTastyTradeData() { try { const response = await fetch(`/api/tastytrade/market-data?session_id=${tastytradeSession}&symbols=SPY,QQQ,AAPL,TSLA`); const data = await response.json(); if (data.status === 'success') { console.log('TastyTrade market data:', data); displayTastyTradeData(data.data); } } catch (error) { console.error('Failed to load TastyTrade data:', error); } } // Helper function for displaying TastyTrade data function displayTastyTradeData(marketData) { // Add live market data section if (marketData && marketData.data) { const liveDataHtml = ` <div class="alert alert-success mt-3"> <h6><i class="fas fa-broadcast-tower me-2"></i>Live TastyTrade Market Data</h6> <div class="row"> ${marketData.data.map(quote => ` <div class="col-md-3 mb-2"> <strong>${quote.symbol}</strong><br> <span class="text-primary">$${quote.last?.toFixed(2) || 'N/A'}</span> <small class="text-muted d-block">Vol: ${quote.volume || 'N/A'}</small> </div> `).join('')} </div> </div> `; // Insert after TastyTrade status section const statusSection = document.getElementById('tastytradeStatus'); if (statusSection) { statusSection.insertAdjacentHTML('afterend', liveDataHtml); } } } // Helper function for showing loading state function showLoading(button) { button.innerHTML = '<i class="fas fa-spinner fa-spin me-2"></i>Connecting...'; button.disabled = true; } // CME Data Management let cmeStatusInterval = null; // Initialize CME status on page load $(document).ready(function() { // Existing initialization... // Load CME status refreshCMEStatus(); // Auto-refresh status every 30 seconds cmeStatusInterval = setInterval(refreshCMEStatus, 30000); }); async function refreshCMEStatus() { try { const response = await fetch('/api/cme/status'); // Check if response is JSON const contentType = response.headers.get('content-type'); if (!contentType || !contentType.includes('application/json')) { throw new Error('Server returned non-JSON response'); } const data = await response.json(); if (data.status === 'success' || data.status === 'error') { updateCMEStatus(data); } } catch (error) { console.error('Failed to refresh CME status:', error); // Show more specific error message const errorMsg = error.message.includes('non-JSON') ? 'Server communication error' : 'Failed to refresh status'; // Show fallback status with better error info updateCMEStatus({ status: 'error', fetch_status: { is_fetching: false, last_fetch: null, last_error: errorMsg }, database_stats: { contracts: 'N/A - Connection issue', trades: 'N/A - Connection issue' } }); } } function updateCMEStatus(statusData) { const statusElement = document.getElementById('cmeStatus'); const statsElement = document.getElementById('cmeStats'); const progressElement = document.getElementById('cmeProgress'); const fetchBtn = document.getElementById('fetchCmeBtn'); const lastFetchElement = document.getElementById('cmeLastFetch'); const lastFetchTimeElement = document.getElementById('cmeLastFetchTime'); // Safety checks for null/undefined data if (!statusData || !statusData.fetch_status || !statusData.database_stats) { console.error('Invalid status data received:', statusData); return; } const fetchStatus = statusData.fetch_status || {}; const dbStats = statusData.database_stats || {}; // Update status with null checks if (fetchStatus.is_fetching) { if (statusElement) { statusElement.textContent = 'Fetching Data...'; statusElement.className = 'text-warning'; } if (progressElement) { progressElement.style.display = 'block'; } if (fetchBtn) { fetchBtn.disabled = true; fetchBtn.innerHTML = '<i class="fas fa-spinner fa-spin me-2"></i>Fetching...'; } } else { if (statusElement) { statusElement.textContent = 'Ready'; statusElement.className = 'text-success'; } if (progressElement) { progressElement.style.display = 'none'; } if (fetchBtn) { fetchBtn.disabled = false; fetchBtn.innerHTML = '<i class="fas fa-download me-2"></i>Fetch with API'; } } // Update database stats with proper null handling const contracts = (dbStats.contracts !== null && dbStats.contracts !== undefined) ? dbStats.contracts : 'N/A'; const trades = (dbStats.trades !== null && dbStats.trades !== undefined) ? dbStats.trades : 'N/A'; if (statsElement) { statsElement.innerHTML = ` <div class="row"> <div class="col-6"> <strong>${contracts}</strong><br> <small class="text-muted">Contracts</small> </div> <div class="col-6"> <strong>${trades}</strong><br> <small class="text-muted">Trades</small> </div> </div> `; } // Show last fetch time if (fetchStatus.last_fetch && lastFetchTimeElement && lastFetchElement) { try { const fetchTime = new Date(fetchStatus.last_fetch); if (!isNaN(fetchTime.getTime())) { lastFetchTimeElement.textContent = `Last updated: ${fetchTime.toLocaleString()}`; lastFetchElement.style.display = 'block'; } } catch (error) { console.warn('Invalid date format for last_fetch:', fetchStatus.last_fetch); } } // Show error if any if (fetchStatus.last_error && statusElement) { statusElement.textContent = 'Error'; statusElement.className = 'text-danger'; console.error('CME fetch error:', fetchStatus.last_error); // Show error notification if (typeof showCMENotification === 'function') { showCMENotification(`CME Error: ${fetchStatus.last_error}`, 'error'); } } } async function fetchCMEData(forceRefresh = false, useAPI = true) { try { const fetchBtn = document.getElementById('fetchCmeBtn'); const method = useAPI ? 'Enhanced API + CSV' : 'Legacy CSV'; fetchBtn.innerHTML = '<i class="fas fa-spinner fa-spin me-2"></i>Initiating...'; fetchBtn.disabled = true; const params = new URLSearchParams(); if (forceRefresh) params.append('force_refresh', 'true'); if (useAPI) params.append('use_api', 'true'); const url = `/api/cme/fetch?${params.toString()}`; const response = await fetch(url, { method: 'POST' }); const data = await response.json(); if (data.status === 'initiated') { // Start monitoring progress monitorCMEFetch(); // Show success message with method info showCMENotification(`${data.message}`, 'info'); } else if (data.status === 'already_running') { showCMENotification('Fetch already in progress', 'warning'); } else if (data.status === 'recent_fetch') { showCMENotification(`Data recently updated: ${data.message}`, 'info'); } } catch (error) { console.error('Failed to fetch CME data:', error); showCMENotification('Failed to start data fetch', 'error'); } finally { // Reset button after delay setTimeout(() => { const fetchBtn = document.getElementById('fetchCmeBtn'); fetchBtn.innerHTML = '<i class="fas fa-download me-2"></i>Fetch with API'; fetchBtn.disabled = false; }, 2000); } } async function previewAPIData() { try { // Show loading notification showCMENotification('Loading CME API preview...', 'info'); const response = await fetch('/api/cme/api-preview?limit=3'); const result = await response.json(); if (result.status === 'success') { const data = result.data; // Create preview modal content const previewContent = ` <div class="row"> <div class="col-12"> <div class="alert alert-info"> <h6><i class="fas fa-rocket me-2"></i>CME Reference Data API Preview</h6> <p class="mb-2">Found <strong>${data.total_contracts}</strong> active event contracts</p> <small>Real-time access to contract metadata, instruments, and market structure</small> </div> </div> </div> <div class="row"> <div class="col-md-6"> <h6><i class="fas fa-file-contract me-2"></i>Sample Contracts</h6> ${data.sample_contracts.map(contract => ` <div class="card card-body mb-2 bg-light"> <h6 class="card-title mb-1">${contract.name || 'Event Contract'}</h6> <p class="card-text small mb-1">${contract.description || 'No description'}</p> <div class="row small text-muted"> <div class="col-6">Status: <span class="badge bg-${contract.status === 'ACTIVE' ? 'success' : 'secondary'}">${contract.status}</span></div> <div class="col-6">Payout: ${contract.fixPayout || 'Variable'}</div> </div> ${contract.instruments_count ? ` <small class="text-primary mt-1"> <i class="fas fa-cogs me-1"></i>${contract.instruments_count} instruments available </small> ` : ''} </div> `).join('')} </div> <div class="col-md-6"> <h6><i class="fas fa-star me-2"></i>API Benefits</h6> <ul class="list-unstyled"> ${data.api_features.map(feature => ` <li class="mb-1"><i class="fas fa-check text-success me-2"></i>${feature}</li> `).join('')} </ul> <h6 class="mt-3"><i class="fas fa-chart-line me-2"></i>Optimization Benefits</h6> <ul class="list-unstyled"> ${data.optimization_benefits.map(benefit => ` <li class="mb-1"><i class="fas fa-arrow-up text-primary me-2"></i>${benefit}</li> `).join('')} </ul> </div> </div> <div class="row mt-3"> <div class="col-12"> <div class="alert alert-success"> <strong>Recommendation:</strong> Use "Enhanced API + CSV" method for optimal performance and data quality. API provides real-time contract metadata while CSV delivers comprehensive trade history. </div> </div> </div> `; // Show in modal document.getElementById('sampleDataContent').innerHTML = previewContent; document.querySelector('#sampleDataModal .modal-title').innerHTML = '<i class="fas fa-rocket me-2"></i>CME Reference Data API Preview'; const modal = new bootstrap.Modal(document.getElementById('sampleDataModal')); modal.show(); } else { showCMENotification(`API preview failed: ${result.message}`, 'error'); } } catch (error) { console.error('Failed to preview API data:', error); showCMENotification('Failed to load API preview', 'error'); } } function monitorCMEFetch() { // Refresh status more frequently during fetch const monitorInterval = setInterval(() => { refreshCMEStatus().then(() => { const statusElement = document.getElementById('cmeStatus'); // Stop monitoring when fetch completes if (!statusElement.textContent.includes('Fetching')) { clearInterval(monitorInterval); // Show completion message if (statusElement.className.includes('text-success')) { showCMENotification('CME data fetch completed successfully!', 'success'); } else if (statusElement.className.includes('text-danger')) { showCMENotification('CME data fetch failed', 'error'); } } }); }, 3000); // Stop monitoring after 2 minutes max setTimeout(() => clearInterval(monitorInterval), 120000); } async function showSampleData() { try { // Show modal const modal = new bootstrap.Modal(document.getElementById('sampleDataModal')); modal.show(); // Fetch sample data const response = await fetch('/api/cme/sample-data?limit=10'); const data = await response.json(); const content = document.getElementById('sampleDataContent'); if (data.status === 'success') { content.innerHTML = ` <div class="row"> <div class="col-md-6"> <h6><i class="fas fa-file-contract me-2"></i>Recent Contracts</h6> <div class="table-responsive"> <table class="table table-sm"> <thead> <tr> <th>Symbol</th> <th>Type</th> <th>Status</th> </tr> </thead> <tbody> ${data.sample_contracts.map(contract => ` <tr> <td><small><code>${contract.symbol}</code></small></td> <td><small>${contract.type}</small></td> <td><small class="${contract.active ? 'text-success' : 'text-muted'}"> ${contract.active ? 'Active' : 'Inactive'} </small></td> </tr> `).join('')} </tbody> </table> </div> </div> <div class="col-md-6"> <h6><i class="fas fa-chart-line me-2"></i>Recent Trades</h6> <div class="table-responsive"> <table class="table table-sm"> <thead> <tr> <th>Time</th> <th>Price</th> <th>Volume</th> </tr> </thead> <tbody> ${data.sample_trades.map(trade => ` <tr> <td><small>${new Date(trade.timestamp).toLocaleTimeString()}</small></td> <td><small><strong>${trade.price.toFixed(4)}</strong></small></td> <td><small>${trade.volume}</small></td> </tr> `).join('')} </tbody> </table> </div> </div> </div> `; } else { content.innerHTML = '<div class="alert alert-warning">Failed to load sample data</div>'; } } catch (error) { console.error('Failed to load sample data:', error); document.getElementById('sampleDataContent').innerHTML = '<div class="alert alert-danger">Error loading sample data</div>'; } } function showCMENotification(message, type = 'info') { const alertClass = { 'success': 'alert-success', 'info': 'alert-info', 'warning': 'alert-warning', 'error': 'alert-danger' }[type] || 'alert-info'; const notification = document.createElement('div'); notification.className = `alert ${alertClass} alert-dismissible fade show position-fixed`; notification.style.cssText = 'top: 80px; right: 20px; z-index: 1050; min-width: 300px;'; notification.innerHTML = ` ${message} <button type="button" class="btn-close" data-bs-dismiss="alert"></button> `; document.body.appendChild(notification); // Auto-dismiss after 5 seconds setTimeout(() => { if (notification.parentNode) { notification.remove(); } }, 5000); } // Cleanup on page unload window.addEventListener('beforeunload', function() { if (cmeStatusInterval) { clearInterval(cmeStatusInterval); } }); </script> {% endblock %}

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/jjsteffen23/dk_mcp_2'

If you have feedback or need assistance with the MCP directory API, please join our Discord server