Compare commits

...

1 Commits

Author SHA1 Message Date
Flatlogic Bot
a3740453b6 riskflux app 2026-02-28 21:16:23 +00:00
12 changed files with 593 additions and 188 deletions

Binary file not shown.

View File

@ -0,0 +1,31 @@
# Generated by Django 5.2.7 on 2026-02-28 20:31
from django.db import migrations, models
class Migration(migrations.Migration):
initial = True
dependencies = [
]
operations = [
migrations.CreateModel(
name='SimulationResult',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('created_at', models.DateTimeField(auto_now_add=True)),
('symbol', models.CharField(default='ES=F', max_length=20)),
('expected_low', models.FloatField()),
('worst_case_5th', models.FloatField()),
('drawdown_prob', models.FloatField()),
('bias', models.CharField(max_length=10)),
('take_profit', models.FloatField()),
('stop_loss', models.FloatField()),
('sentiment_score', models.FloatField()),
('regime', models.IntegerField()),
('summary', models.TextField(blank=True)),
],
),
]

View File

@ -1,3 +1,25 @@
from django.db import models from django.db import models
# Create your models here. class SimulationResult(models.Model):
created_at = models.DateTimeField(auto_now_add=True)
symbol = models.CharField(max_length=20, default="ES=F")
# Risk Metrics
expected_low = models.FloatField()
worst_case_5th = models.FloatField()
drawdown_prob = models.FloatField()
# Trading Bias
bias = models.CharField(max_length=10) # LONG, SHORT, NEUTRAL
take_profit = models.FloatField()
stop_loss = models.FloatField()
# Sentiment
sentiment_score = models.FloatField() # -1 to 1
regime = models.IntegerField() # 0, 1, 2...
# JSON or Text field for simulation paths if needed, but for now we'll keep it simple
summary = models.TextField(blank=True)
def __str__(self):
return f"{self.symbol} Risk - {self.created_at.strftime('%Y-%m-%d %H:%M')}"

136
core/risk_engine.py Normal file
View File

@ -0,0 +1,136 @@
import os
import yfinance as yf
import pandas as pd
import numpy as np
import feedparser
from bs4 import BeautifulSoup
from statsmodels.tsa.regime_switching.markov_regression import MarkovRegression
from scipy.stats import norm, t
from datetime import datetime, timedelta
class RiskEngine:
def __init__(self, symbol="ES=F"):
self.symbol = symbol
self.lookback_days = 250
def get_market_data(self):
"""Fetch historical ES futures data from Yahoo Finance."""
end_date = datetime.now()
start_date = end_date - timedelta(days=self.lookback_days)
data = yf.download(self.symbol, start=start_date, end=end_date)
if data.empty:
raise ValueError("No market data fetched.")
# Calculate daily log returns
# Handle potential multi-index if symbol is a single string but yfinance returns multi-index
if isinstance(data.columns, pd.MultiIndex):
close_col = ('Close', self.symbol) if ( 'Close', self.symbol) in data.columns else data.columns[0]
close_data = data[close_col]
else:
close_data = data['Close']
log_returns = np.log(close_data / close_data.shift(1))
processed_data = pd.DataFrame({
'Close': close_data,
'Log_Returns': log_returns
})
return processed_data.dropna()
def get_sentiment(self):
"""Collect sentiment from Google News RSS."""
rss_url = f"https://news.google.com/rss/search?q={self.symbol}+futures+stock+market&hl=en-US&gl=US&ceid=US:en"
feed = feedparser.parse(rss_url)
positive_words = {'bull', 'rally', 'surge', 'growth', 'positive', 'gain', 'strong', 'uptrend', 'recovery', 'high'}
negative_words = {'bear', 'crash', 'plunge', 'recession', 'negative', 'drop', 'weak', 'downtrend', 'risk', 'low', 'crisis'}
scores = []
for entry in feed.entries[:20]: # Last 20 headlines
headline = entry.title.lower()
p_count = sum(1 for w in positive_words if w in headline)
n_count = sum(1 for w in negative_words if w in headline)
score = (p_count - n_count) / (p_count + n_count + 1)
scores.append(score)
return np.mean(scores) if scores else 0.0
def fit_markov_regime(self, data):
"""Model daily return dynamics with a 2-state Markov transition framework."""
# 0: Low Vol, 1: High Vol/Bearish
model = MarkovRegression(data['Log_Returns'], k_regimes=2, trend='c', switching_variance=True)
res = model.fit(disp=False)
# Latest regime probability
current_regime = 0 if res.smoothed_marginal_probabilities[0].iloc[-1] > 0.5 else 1
# Regime parameters
regime_params = {
'mu': res.params[['const[0]', 'const[1]']].values,
'sigma': np.sqrt(res.params[['sigma2[0]', 'sigma2[1]']].values)
}
return current_regime, regime_params
def run_simulation(self):
"""Main entry point to run the risk simulation."""
data = self.get_market_data()
sentiment = self.get_sentiment()
regime, params = self.fit_markov_regime(data)
# Sentiment adjustment
# Sentiment (negative) increases volatility and jump intensity
vol_adj = 1.0 - (sentiment * 0.5) # If sentiment is -1, vol_adj is 1.5
current_close = float(data['Close'].iloc[-1])
mu = float(params['mu'][regime])
sigma = float(params['sigma'][regime] * vol_adj)
# Monte Carlo Simulation (Intraday - 100 steps for a day)
n_paths = 5000
n_steps = 100
dt = 1.0 / n_steps
# Fat-tailed moves (Student's t-distribution)
df = 5 # Degrees of freedom for fat tails
shocks = t.rvs(df, size=(n_paths, n_steps)) * sigma * np.sqrt(dt)
paths = np.zeros((n_paths, n_steps + 1))
paths[:, 0] = current_close
for t_step in range(1, n_steps + 1):
paths[:, t_step] = paths[:, t_step - 1] * np.exp((mu - 0.5 * sigma**2) * dt + shocks[:, t_step - 1])
# Metrics
intraday_lows = np.min(paths, axis=1)
expected_low = np.mean(intraday_lows)
worst_case_5th = np.percentile(intraday_lows, 5)
# Prob of 1% drawdown
drawdowns = (np.min(paths, axis=1) - current_close) / current_close
prob_1pct_drawdown = np.mean(drawdowns <= -0.01) * 100 # In percentage
# Directional Bias & TP/SL
# Bias is driven by (Sentiment + Mu)
total_bias_score = sentiment * 0.3 + mu * 0.7
if total_bias_score > 0.0005:
bias = "LONG"
tp = current_close + (2 * sigma * current_close)
sl = current_close - (1.5 * sigma * current_close)
elif total_bias_score < -0.0005:
bias = "SHORT"
tp = current_close - (2 * sigma * current_close)
sl = current_close + (1.5 * sigma * current_close)
else:
bias = "NEUTRAL"
tp = current_close + (1 * sigma * current_close)
sl = current_close - (1 * sigma * current_close)
return {
'expected_low': expected_low,
'worst_case_5th': worst_case_5th,
'drawdown_prob': prob_1pct_drawdown,
'bias': bias,
'tp': tp,
'sl': sl,
'sentiment': sentiment,
'regime': regime
}

View File

@ -1,25 +1,85 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en"> <html lang="en" data-bs-theme="dark">
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<title>{% block title %}Knowledge Base{% endblock %}</title> <meta name="viewport" content="width=device-width, initial-scale=1.0">
{% if project_description %} <title>{% block title %}ES Risk Dashboard{% endblock %}</title>
<meta name="description" content="{{ project_description }}"> <meta name="description" content="S&P 500 Futures Risk Analysis & Scenario Simulation Dashboard">
<meta property="og:description" content="{{ project_description }}">
<meta property="twitter:description" content="{{ project_description }}"> <!-- Fonts -->
{% endif %} <link rel="preconnect" href="https://fonts.googleapis.com">
{% if project_image_url %} <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<meta property="og:image" content="{{ project_image_url }}"> <link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;600;800&family=JetBrains+Mono:wght@500&display=swap" rel="stylesheet">
<meta property="twitter:image" content="{{ project_image_url }}">
{% endif %} <!-- Bootstrap 5 CSS & Icons -->
{% load static %} <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet">
<link rel="stylesheet" href="{% static 'css/custom.css' %}?v={{ deployment_timestamp }}"> <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.2/font/bootstrap-icons.min.css">
{% block head %}{% endblock %}
<style>
:root {
--neon-green: #39FF14;
--neon-blue: #00E5FF;
--dark-charcoal: #121212;
--slate-gray: #1E1E1E;
--off-white: #f8f9fa; /* Brighter off-white for better contrast */
}
body {
font-family: 'Inter', sans-serif;
background-color: var(--dark-charcoal);
color: var(--off-white);
}
.font-mono { font-family: 'JetBrains Mono', monospace; }
.navbar-brand { font-weight: 800; letter-spacing: -1px; }
.bg-dark-900 { background-color: #0B0B0B; }
.text-neon-green { color: var(--neon-green) !important; }
.text-neon-blue { color: var(--neon-blue) !important; }
/* Improved text-muted for dark backgrounds */
.text-muted { color: #a0a0a0 !important; }
.hover-white:hover { color: white !important; }
/* Custom Scrollbar */
::-webkit-scrollbar { width: 8px; }
::-webkit-scrollbar-track { background: #1a1a1a; }
::-webkit-scrollbar-thumb { background: #333; border-radius: 4px; }
::-webkit-scrollbar-thumb:hover { background: #444; }
</style>
</head> </head>
<body class="text-light">
<nav class="navbar navbar-expand-lg navbar-dark bg-dark-900 border-bottom border-secondary border-opacity-25 py-3">
<div class="container">
<a class="navbar-brand text-neon-green d-flex align-items-center" href="{% url 'index' %}">
<i class="bi bi-activity me-2"></i>
<span class="text-white">RISK</span>FLUX
</a>
<div class="navbar-nav ms-auto">
<a class="nav-link small text-muted hover-white d-flex align-items-center" href="/admin/">
<i class="bi bi-shield-lock me-1"></i> ADMIN PANEL
</a>
</div>
</div>
</nav>
<body> <main>
{% block content %}{% endblock %} {% block content %}{% endblock %}
</main>
<footer class="py-5 text-center border-top border-secondary border-opacity-10 mt-5">
<div class="container">
<p class="small text-muted mb-0">© 2026 RISKFLUX. MARKET SIMULATION ENGINE.</p>
<p class="small text-muted mb-0 mt-2">Quantitative risk estimation for educational purposes only.</p>
</div>
</footer>
<!-- Bootstrap JS Bundle -->
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js"></script>
<script>
// Initialize tooltips
var tooltipTriggerList = [].slice.call(document.querySelectorAll('[data-bs-toggle="tooltip"]'))
var tooltipList = tooltipTriggerList.map(function (tooltipTriggerEl) {
return new bootstrap.Tooltip(tooltipTriggerEl)
})
</script>
</body> </body>
</html>
</html>

View File

@ -1,145 +1,284 @@
{% extends "base.html" %} {% extends 'base.html' %}
{% load static %}
{% block title %}{{ project_name }}{% endblock %}
{% block head %}
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;700&display=swap" rel="stylesheet">
<style>
:root {
--bg-color-start: #6a11cb;
--bg-color-end: #2575fc;
--text-color: #ffffff;
--card-bg-color: rgba(255, 255, 255, 0.01);
--card-border-color: rgba(255, 255, 255, 0.1);
}
* {
box-sizing: border-box;
}
body {
margin: 0;
font-family: 'Inter', sans-serif;
background: linear-gradient(45deg, var(--bg-color-start), var(--bg-color-end));
color: var(--text-color);
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
text-align: center;
overflow: hidden;
position: relative;
}
body::before {
content: '';
position: absolute;
inset: 0;
background-image: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' width='100' height='100' viewBox='0 0 100 100'><path d='M-10 10L110 10M10 -10L10 110' stroke-width='1' stroke='rgba(255,255,255,0.05)'/></svg>");
animation: bg-pan 20s linear infinite;
z-index: -1;
}
@keyframes bg-pan {
0% {
background-position: 0% 0%;
}
100% {
background-position: 100% 100%;
}
}
main {
padding: 2rem;
}
.card {
background: var(--card-bg-color);
border: 1px solid var(--card-border-color);
border-radius: 16px;
padding: 2.5rem 2rem;
backdrop-filter: blur(20px);
-webkit-backdrop-filter: blur(20px);
box-shadow: 0 12px 36px rgba(0, 0, 0, 0.25);
}
h1 {
font-size: clamp(2.2rem, 3vw + 1.2rem, 3.2rem);
font-weight: 700;
margin: 0 0 1.2rem;
letter-spacing: -0.02em;
}
p {
margin: 0.5rem 0;
font-size: 1.1rem;
opacity: 0.92;
}
.loader {
margin: 1.5rem auto;
width: 56px;
height: 56px;
border: 4px solid rgba(255, 255, 255, 0.25);
border-top-color: #fff;
border-radius: 50%;
animation: spin 1s linear infinite;
}
@keyframes spin {
to {
transform: rotate(360deg);
}
}
.runtime code {
background: rgba(0, 0, 0, 0.25);
padding: 0.15rem 0.45rem;
border-radius: 4px;
font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
}
.sr-only {
position: absolute;
width: 1px;
height: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
border: 0;
}
footer {
position: absolute;
bottom: 1rem;
width: 100%;
text-align: center;
font-size: 0.85rem;
opacity: 0.75;
}
</style>
{% endblock %}
{% block content %} {% block content %}
<main> <div class="container py-5">
<div class="card"> <!-- Header Section -->
<h1>Analyzing your requirements and generating your app…</h1> <header class="mb-5 text-center fade-in">
<div class="loader" role="status" aria-live="polite" aria-label="Applying initial changes"> <h1 class="display-3 fw-bold text-white mb-2 font-mono">
<span class="sr-only">Loading…</span> ES Risk <span class="text-neon-green">Simulator</span>
</h1>
<p class="lead text-muted">S&P 500 Futures Intraday Scenarios & Regime Analysis</p>
</header>
{% if error %}
<div class="alert alert-danger bg-danger bg-opacity-10 border-danger text-danger rounded-4 mb-4 d-flex align-items-center">
<i class="bi bi-exclamation-triangle-fill me-2 fs-4"></i>
<div><strong>Engine Error:</strong> {{ error }}</div>
</div> </div>
<p class="hint">AppWizzy AI is collecting your requirements and applying the first changes.</p> {% endif %}
<p class="hint">This page will refresh automatically as the plan is implemented.</p>
<p class="runtime"> <div class="row g-4">
Runtime: Django <code>{{ django_version }}</code> · Python <code>{{ python_version }}</code> <!-- Main Analysis Panel -->
— UTC <code>{{ current_time|date:"Y-m-d H:i:s" }}</code> <div class="col-lg-8">
</p> <div class="card bg-slate border-0 shadow-lg rounded-5 overflow-hidden mb-4">
</div> <div class="card-body p-4 p-md-5">
</main> <div class="d-flex justify-content-between align-items-center mb-5">
<footer> <div class="d-flex align-items-center">
Page updated: {{ current_time|date:"Y-m-d H:i:s" }} (UTC) <i class="bi bi-cpu text-neon-green fs-2 me-3"></i>
</footer> <h2 class="h4 text-white mb-0">Analysis Control</h2>
</div>
<form action="{% url 'run_simulation' %}" method="post">
{% csrf_token %}
<button type="submit" class="btn btn-neon-green px-4 py-2 fw-bold text-dark rounded-pill">
<i class="bi bi-lightning-charge-fill me-1"></i> RE-RUN ENGINE
</button>
</form>
</div>
{% if latest %}
<div class="row g-4 mb-5">
<div class="col-md-4">
<div class="stat-card p-4 rounded-4 bg-dark-900 border-top border-4 border-neon-blue">
<div class="d-flex justify-content-between align-items-start mb-2">
<label class="text-muted small fw-bold">EXPECTED LOW</label>
<i class="bi bi-info-circle text-muted small" data-bs-toggle="tooltip" title="The average lowest price projected across 1,000 simulations for today."></i>
</div>
<div class="h2 text-white font-mono mb-0">{{ latest.expected_low|floatformat:2 }}</div>
<div class="small text-neon-blue mt-1">Simulated Mean</div>
</div>
</div>
<div class="col-md-4">
<div class="stat-card p-4 rounded-4 bg-dark-900 border-top border-4 border-danger">
<div class="d-flex justify-content-between align-items-start mb-2">
<label class="text-muted small fw-bold">TAIL RISK (VaR)</label>
<i class="bi bi-info-circle text-muted small" data-bs-toggle="tooltip" title="Value at Risk: 95% of simulated paths stay above this level."></i>
</div>
<div class="h2 text-white font-mono mb-0">{{ latest.worst_case_5th|floatformat:2 }}</div>
<div class="small text-danger mt-1">5th Percentile</div>
</div>
</div>
<div class="col-md-4">
<div class="stat-card p-4 rounded-4 bg-dark-900 border-top border-4 border-warning">
<div class="d-flex justify-content-between align-items-start mb-2">
<label class="text-muted small fw-bold">1% DRAWDOWN</label>
<i class="bi bi-info-circle text-muted small" data-bs-toggle="tooltip" title="The probability that price drops more than 1% from current levels today."></i>
</div>
<div class="h2 text-white font-mono mb-0">{{ latest.drawdown_prob|floatformat:2 }}%</div>
<div class="small text-warning mt-1">Incident Prob</div>
</div>
</div>
</div>
<!-- Bias and Targets -->
<div class="p-4 bg-dark-900 rounded-5 border border-secondary border-opacity-10 position-relative overflow-hidden">
<div class="glass-shine"></div>
<div class="row align-items-center">
<div class="col-md-6 border-end border-secondary border-opacity-25 py-3">
<div class="d-flex align-items-center mb-2">
<span class="badge rounded-pill {% if latest.bias == 'LONG' %}bg-neon-green{% elif latest.bias == 'SHORT' %}bg-danger{% else %}bg-secondary{% endif %} text-dark me-2">
{{ latest.bias }}
</span>
<h3 class="h4 mb-0 text-white">Daily Bias</h3>
<i class="bi bi-info-circle ms-2 text-muted small" data-bs-toggle="tooltip" title="Aggregated recommendation based on Sentiment, Regime, and Intraday Momentum."></i>
</div>
<p class="text-muted mb-0">
<i class="bi bi-grid-1x2 me-1"></i>
Regime: <strong>{{ latest.regime|yesno:"High Volatility (Risk-Off),Low Volatility (Risk-On)" }}</strong>
</p>
</div>
<div class="col-md-6 text-md-center py-3">
<div class="d-flex justify-content-around">
<div>
<div class="small text-muted mb-1 text-uppercase">Target Profit</div>
<div class="h4 text-neon-green font-mono mb-0">{{ latest.take_profit|floatformat:2 }}</div>
</div>
<div>
<div class="small text-muted mb-1 text-uppercase">Stop Loss</div>
<div class="h4 text-danger font-mono mb-0">{{ latest.stop_loss|floatformat:2 }}</div>
</div>
</div>
</div>
</div>
</div>
{% else %}
<div class="text-center py-5">
<i class="bi bi-database-dash display-1 text-muted opacity-50 mb-4"></i>
<p class="text-muted">No analysis available. Click the button to trigger the engine.</p>
</div>
{% endif %}
</div>
</div>
<!-- Sentiment & Explanation Section -->
<div class="card bg-slate border-0 rounded-5 p-4 shadow-sm">
<div class="d-flex justify-content-between align-items-center mb-3">
<h3 class="h5 text-white mb-0 d-flex align-items-center">
<i class="bi bi-graph-up-arrow text-neon-blue me-2"></i> Real-time Sentiment
</h3>
<span class="small text-muted font-mono">RSS ANALYSIS FEED</span>
</div>
<div class="sentiment-bar-container mb-2">
{% if latest %}
<div class="sentiment-bar" style="width: 50%; margin-left: {% if latest.sentiment_score > 0 %}50{% else %}0{% endif %}%; background: {% if latest.sentiment_score > 0 %}#39FF14{% else %}#ff4444{% endif %}; box-shadow: 0 0 15px {% if latest.sentiment_score > 0 %}#39FF14{% else %}#ff4444{% endif %}80;"></div>
{% endif %}
</div>
<div class="d-flex justify-content-between small text-muted font-mono">
<span class="d-flex align-items-center"><i class="bi bi-arrow-down-circle me-1"></i> Bearish</span>
<span>Neutral</span>
<span class="d-flex align-items-center">Bullish <i class="bi bi-arrow-up-circle ms-1"></i></span>
</div>
<hr class="my-4 border-secondary border-opacity-25">
<div class="row g-4">
<div class="col-md-6">
<h4 class="h6 text-white mb-2 fw-bold">What is this?</h4>
<p class="small text-muted">This engine simulates 1,000 potential price paths for the S&P 500 E-mini (ES) futures. It combines historical volatility, a Markov Switching Model for regime detection, and real-time sentiment analysis to estimate intraday risk boundaries.</p>
</div>
<div class="col-md-6">
<h4 class="h6 text-white mb-2 fw-bold">How to use?</h4>
<p class="small text-muted">Watch the <strong>Tail Risk (VaR)</strong> level. In high volatility regimes, price tends to test these boundaries. The <strong>Bias</strong> suggests a directional lean based on combined indicators.</p>
</div>
</div>
</div>
</div>
<!-- Sidebar / History -->
<div class="col-lg-4">
<div class="card bg-slate border-0 rounded-5 shadow-lg mb-4">
<div class="card-body p-4">
<div class="d-flex align-items-center mb-4">
<i class="bi bi-clock-history text-muted fs-4 me-2"></i>
<h3 class="h5 text-white mb-0">Engine History</h3>
</div>
<div class="history-list overflow-auto" style="max-height: 400px;">
{% for item in history %}
<div class="history-item p-3 mb-2 rounded-4 bg-dark-900 transition-all border border-transparent hover-border-neon">
<div class="d-flex justify-content-between align-items-center">
<div>
<div class="text-white small fw-bold font-mono">{{ item.created_at|date:"M d, H:i" }}</div>
<div class="small {% if item.bias == 'LONG' %}text-neon-green{% elif item.bias == 'SHORT' %}text-danger{% else %}text-muted{% endif %}">
{{ item.bias }} BIAS
</div>
</div>
<div class="text-neon-blue font-mono">{{ item.expected_low|floatformat:1 }}</div>
</div>
</div>
{% empty %}
<div class="text-muted small text-center py-4">No history records found.</div>
{% endfor %}
</div>
</div>
</div>
<div class="p-4 bg-neon-green bg-opacity-10 border border-neon-green border-opacity-25 rounded-5">
<div class="d-flex align-items-center mb-3">
<i class="bi bi-shield-check text-neon-green fs-4 me-2"></i>
<h4 class="h6 text-neon-green fw-bold mb-0">System Integrity</h4>
</div>
<div class="small text-muted font-mono">
<div class="d-flex justify-content-between mb-2">
<span>Markov Chain:</span>
<span class="text-neon-green">ACTIVE</span>
</div>
<div class="d-flex justify-content-between mb-2">
<span>Data Feed:</span>
<span class="text-white">YFINANCE</span>
</div>
<div class="d-flex justify-content-between">
<span>Bias Engine:</span>
<span class="text-white">KALMAN-MOD</span>
</div>
</div>
</div>
</div>
</div>
</div>
<style>
:root {
--neon-green: #39FF14;
--neon-blue: #00E5FF;
--dark-charcoal: #121212;
--slate-gray: #1E1E1E;
--dark-900: #0B0B0B;
}
.bg-slate { background-color: var(--slate-gray); }
.bg-dark-900 { background-color: var(--dark-900); }
.text-neon-green { color: var(--neon-green) !important; }
.text-neon-blue { color: var(--neon-blue) !important; }
/* Stronger muted text for readability */
.text-muted { color: #a0a0a0 !important; }
.btn-neon-green {
background-color: var(--neon-green);
border: none;
box-shadow: 0 0 15px rgba(57, 255, 20, 0.3);
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
}
.btn-neon-green:hover {
background-color: #2ED110;
box-shadow: 0 0 25px rgba(57, 255, 20, 0.5);
transform: translateY(-2px);
}
.stat-card {
transition: all 0.3s ease;
border-bottom: 1px solid rgba(255,255,255,0.05);
}
.stat-card:hover {
transform: translateY(-5px);
background-color: #151515 !important;
}
.sentiment-bar-container {
height: 8px;
background: #333;
border-radius: 10px;
overflow: hidden;
position: relative;
}
.sentiment-bar {
height: 100%;
width: 50%;
transition: all 1.2s cubic-bezier(0.16, 1, 0.3, 1);
}
.history-item:hover {
background-color: #1a1a1a !important;
border-color: rgba(0, 229, 255, 0.3) !important;
cursor: pointer;
}
.glass-shine {
position: absolute;
top: 0;
left: -100%;
width: 50%;
height: 100%;
background: linear-gradient(120deg, transparent, rgba(255,255,255,0.05), transparent);
transition: all 0.6s;
}
.bg-dark-900:hover .glass-shine {
left: 150%;
}
.fade-in {
animation: fadeIn 0.8s ease-out;
}
@keyframes fadeIn {
from { opacity: 0; transform: translateY(10px); }
to { opacity: 1; transform: translateY(0); }
}
/* Responsive overrides */
@media (max-width: 768px) {
.stat-card { margin-bottom: 10px; }
}
</style>
{% endblock %} {% endblock %}

View File

@ -1,7 +1,7 @@
from django.urls import path from django.urls import path
from . import views
from .views import home
urlpatterns = [ urlpatterns = [
path("", home, name="home"), path('', views.index, name='index'),
] path('simulate/', views.run_simulation, name='run_simulation'),
]

View File

@ -1,25 +1,42 @@
import os from django.shortcuts import render, redirect
import platform from .models import SimulationResult
from .risk_engine import RiskEngine
from django import get_version as django_version import json
from django.shortcuts import render
from django.utils import timezone
def home(request):
"""Render the landing screen with loader and environment details."""
host_name = request.get_host().lower()
agent_brand = "AppWizzy" if host_name == "appwizzy.com" else "Flatlogic"
now = timezone.now()
def index(request):
"""Main dashboard showing the latest analysis and a list of historical runs."""
latest = SimulationResult.objects.order_by('-created_at').first()
history = SimulationResult.objects.order_by('-created_at')[1:10]
context = { context = {
"project_name": "New Style", 'latest': latest,
"agent_brand": agent_brand, 'history': history,
"django_version": django_version(), 'status': 'Ready'
"python_version": platform.python_version(),
"current_time": now,
"host_name": host_name,
"project_description": os.getenv("PROJECT_DESCRIPTION", ""),
"project_image_url": os.getenv("PROJECT_IMAGE_URL", ""),
} }
return render(request, "core/index.html", context) return render(request, 'core/index.html', context)
def run_simulation(request):
"""Executes the risk engine and stores the result."""
if request.method == 'POST':
try:
engine = RiskEngine()
results = engine.run_simulation()
# Save to DB
sim = SimulationResult.objects.create(
expected_low=results['expected_low'],
worst_case_5th=results['worst_case_5th'],
drawdown_prob=results['drawdown_prob'],
bias=results['bias'],
take_profit=results['tp'],
stop_loss=results['sl'],
sentiment_score=results['sentiment'],
regime=results['regime'],
summary=f"Analysis for {engine.symbol} completed."
)
return redirect('index')
except Exception as e:
# For simplicity, pass error back to index
return render(request, 'core/index.html', {'error': str(e), 'status': 'Error'})
return redirect('index')