From a3740453b6c3470b707f8db2601504266c409d4a Mon Sep 17 00:00:00 2001 From: Flatlogic Bot Date: Sat, 28 Feb 2026 21:16:23 +0000 Subject: [PATCH] riskflux app --- core/__pycache__/models.cpython-311.pyc | Bin 209 -> 1594 bytes core/__pycache__/risk_engine.cpython-311.pyc | Bin 0 -> 7535 bytes core/__pycache__/urls.cpython-311.pyc | Bin 347 -> 457 bytes core/__pycache__/views.cpython-311.pyc | Bin 1364 -> 2283 bytes core/migrations/0001_initial.py | 31 ++ .../__pycache__/0001_initial.cpython-311.pyc | Bin 0 -> 1715 bytes core/models.py | 24 +- core/risk_engine.py | 136 ++++++ core/templates/base.html | 100 ++++- core/templates/core/index.html | 421 ++++++++++++------ core/urls.py | 8 +- core/views.py | 61 ++- 12 files changed, 593 insertions(+), 188 deletions(-) create mode 100644 core/__pycache__/risk_engine.cpython-311.pyc create mode 100644 core/migrations/0001_initial.py create mode 100644 core/migrations/__pycache__/0001_initial.cpython-311.pyc create mode 100644 core/risk_engine.py diff --git a/core/__pycache__/models.cpython-311.pyc b/core/__pycache__/models.cpython-311.pyc index 18a063c85a879cc83d00a9a0383835944a371483..9a6d89c63f12d769e2f8dd1fafda4bdcfd026bea 100644 GIT binary patch literal 1594 zcmaJ>&2Jk;6rc51{I!nl*rpOKxD9J(jS^p=icp|Pl#~V%+9nFZLRzgosaiK7Z7L zIJA!B@EKQSfkku^6U}a1!ow+asa&)L9)h5nfKe?FKqR;`!XWHv;27`|`20}|4=o}i z9Yd(o@G&HEGESy8HMEJ2Y>r`ZGEz`2b|o6W5=~4*kDN|Tn**bsZPr@9ud2vIU7)@q}p*z#W1^yit$+v z4m${ax&G<09AI%>-BUDTY&qL(3X`S^E@!-hWWnN0gLk;Dsm5+&Tr1e+jl|pHVgi-=55`_GNYX{Ndqn5o}oG%`vr0?e?eO|&v>8nqq zRXNBa_P$;>H5PAJM0E&OREI@v$7(t)oj|4`n`lj&hc3QZsBW7&sdnle!|7DX9%%pv zR<&zdyLMY`kZQxUNY(G)h4wz1QWQ8zQ4X$6GPrPwT!V9M8H9@l*}~Hg`_t?29y!1L z{8#zT%krK6=MTK{Lt1|51O4dw1sJ0>InSbsVyHS%6c$$$h}qHjI;ki>c2vzrEY2qr z@4~${;5N%GqG2n=_hMgctCp{eT#qknrs@ngSd#3uNrO|NnO&BG+u4rNP;H`o3)|DQf-!S)Lp_ink|RLY{zVauWhqwn;4u&!%=L`4NKlP9I{3H&@5t+ zEkIdpgX~=fpRzl;u3GyRZ_huGH3O5C;ez+aQ1DCHuR*xuXONM41)7mweALe@dYMI< zS#(zh;*G;iD&F`b`(m>%E_vb-6_?!Q^9agGz1wu=18=58XG-ojgM6vCN%JKyKS%R( z?%DwGWtx+`T$$#|?kadBuOHr~iFc2zexl+fDl}1X?+&uFy%NpNdRd8PCHLz=`erXe z(>J~JEKSe4_rdL*xn7eN%3eXH1=;;}AQpK>MNhm%#aqKvrr$qo($srL8~s$pOI2v9 z;@&$C3E>Ul9KBuolyElIM le+S|`CNe%_+QK&e=Yz3 literal 209 zcmZ3^%ge<81QK_rWm*F1#~=<2FhLogg@BCd3@HpLj5!Rsj8Tk?3@J>(44TX@K?*b( zZ?Wa(r=;c-`)M-W;!Md(%uCPLOGzqX21>4E_zY6>OHV%|KQ~psG^sSNq*On(A~m_R zB)>?%JijQrxF9h(RX;huC{-U~j9x+IFAf_ZyEG@&u80Guoe_wOWr4&8W=2NF8w@fR Ku%RM0pb7wG3pAVn diff --git a/core/__pycache__/risk_engine.cpython-311.pyc b/core/__pycache__/risk_engine.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..36aaabcf38a17e9fa47d88e9afc96c1fc55c73fd GIT binary patch literal 7535 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 literal 0 HcmV?d00001 diff --git a/core/__pycache__/urls.cpython-311.pyc b/core/__pycache__/urls.cpython-311.pyc index ebb8c6ea5957e01e2e132c7f2744cb84e6f77cdc..df0ebbcfc3928a759f63fb565bce624aa67dcaa2 100644 GIT binary patch literal 457 zcmZ8cJ4*vW5T3o;yUQiSfP#(oAtE{KMKD;4AU08uGrJ@g?-BNHO|(jx!op5_K@lzd zDHli)uC+=RNSDf4lN51wc6J`$?0oZHEam~_>g?6~#`i}BD>0YOtc}hyFkr-ofYb>A zrZL^u0==#i(0~(0x!$I$MrM4OZ#uvy-i7>OEW{YA49oq;G_|_P>~pB(Ckj*{8SS`9 zYeE)*ap&=FoIz%IA>%z&4&8u1*s&K#-%YraZ3r1&FGDX1Pb*edU~M;SMpY^NSSUI| zZ6y>9VJTyy$qHD;SqT?m`~fpe!F=CoMFDr@jSLg%@E&i-Boa3ZE&X%2`uBk z)z1AqcNj!W`us?guvt-#8Jek12pPj}x~^l`O4oI2f?@Yh2AhM6$IF*)O3Oo99?|lc g<}kbS#7EnE>A`VIYeQNa(c09|OIp96jws@wUt3mmUjP6A delta 251 zcmX@fe49yqIWI340}x2uotBveq#uJgFu)3Be72dWu3DeMx`u5TGXukFAclZ+#weB) z_Fx80j+Y<-O~zX+1&JjYFBzenjQrfxTMR`YV?c6wiMgqMnyk0DQ?e5C()0C7i*kyK zK!)97Ez3+TF9s{T#SIh&no^Qllvlix;WJR0;g^nnM*d`ZMiVYRAP;1EvDf5SMk$L2 s4B{71(FZmLR?Y^O4xx^a8Eh9=QUCw| diff --git a/core/__pycache__/views.cpython-311.pyc b/core/__pycache__/views.cpython-311.pyc index 8d204fa83f3150a3294bfb86b56b16ef24ab87c4..948796c610c9d616a7d3f6fdcb5185651cc5ce3b 100644 GIT binary patch literal 2283 zcmbtVO-vg{6rQ!$YizTI*u;Uvz*dkDH^o+}l=RR<3WT5@l15Nf4T)+ko&hhcz0SdMj>0@|) zZ+_mso%g+Of0E@O0{QalkJ>Q_p})9O7tg-2I}FBsgb@~WloKX}oM+M_And_j-J269 zMb{Q}Urw5oz(&}o`zQTax{W4Vupe{)`zBDLuLH8wYzpV9K*kbsw3a>oVKew_bmV`jY#L zg$>xTb+C)ac}q56W~(u~Ec~A*@XPwf({&Kdvm`8eu!wzY-es>DXe^*5grz0#24u9= z$Os!91hzThZueB(sL3kk0y)#5q++Q|h+Vy0>q*{imUK}kx3 z>dhy!W=>D|D4+&8eq(AD>d2fHgF!WUP@suGHJ+0mnRq^s%|+oUQ2wKBFBM6Hp#1Lb2MY|d0dLsn?0EDr6$ zBT*A7Wtiaay!$7h>poO-mTz$d3v(_S=^p`PHfoE|n>bq%-i_Kf_IXVH*84KcFVU5C zUeC7#u=X1I!1Eqpk>jw*^EG)=ljm>pTAIATfro=j!fYeI?-36D;C;}#0XW}kU>$JZ zc91BRn|pEs^&zwUV7(vFQ_G?mJ(z(`37fq7`?4f9N5E~kea+L{Ng2;Igbyu?x5SD4 z-;z*5^WJNyB>ZHf28&wG5eVbZ=1if`4zTFS zy5gr;J2c!1dgc$`zO@?L_VC%1xpTNSs!B;OqK%v}<*s+;`@8@1qO9O20|v@oVLwNf?#rbt`(k-1_Et z2~zd(FktMppw^DNW0g?c3dPG}ob|xXd^>z-xEDR{4UTkpA19QNHt&;w0QQqMALvBT zX~(l_e#S_`7loR@xy&s|txi(Tz(i*?nh$Zzr)$-zRb8BAP(j{=ZZ&>JG{$XSo>wiO zz}ccs&eI`q`Nx(~P*txW2sRolziZg2zuY`*)K_jEHVUn{e^oIkoUNjU>g*J{tLSaz G=JYQ_A}Emn literal 1364 zcmZ`(&1)M+6ra_{dS%J>I!c! z|D2kdL_iDu-_09gg#HmqK%t><`ZWm8kbw-zLiw{@%1fY!tdJefM7AQl zBhn19Sa6Ea_&F0f52+#t(zs7E+?3c%aE4Gt31lN`$VZUXaWDY%0l$fN{S4($*^jWf zAQFOZ8L?*M2p%0Y9=dd7Ae9|G&s?)vuje~ z*w|s3fmzYCyi6leblsZSXw)-0vAJ@~b$=8ZkKMM4%pxUIZ^X86P1|903-h@L+xPEo zRqQc33p$+=>?7eip%aJUJ?4psnxMCzWy{3I+3KUJ!>U=lhxIBWG+QI|iRTt| zob~hDHF3?$xOE;8-gF7B3n+Sj0BfPw>ijEJJ5jZcy3$owUa6}m>S{+#chz)jv!|tA z{CuKaZ)?{N(g*36i>>ealjojZ{Vnq})5;BG^zo;?`IUZhwUbPDlj(kPrJMYslf2eV zUh6F^_AXrPFJC&Ww^QpcL!ISZcRANzT0Z=#edVjazv(R9>@M9L%*JNq0Rq;#^X5EC zoIAMEUcCCE)QPWk<7@56+9@On0Hh1B(RpB8KAS2P06puedS=OZWkMOW!1G(l6GL;A z0R;Uy__hCq=tXh$6JT$Z8#Xbj7G9^9K^1=i?=i4JSdye3inaW&hh|#-_ZofP9$!6l Xxjnvm=u&%p4P;gNa)91vejfh;ew4%O;)d3-Radi2hlqv+pzgFsC)s;yD7^D|<`QyE9&k+o@Xb(%Yla05 zMs~!}0U&@7)r{>#uQWX1K^R2N#Z#Kh8Qp`mC4jNOGB(lx{ych0eVoyKWfKc*f`Tv| zh=cL-#Hm27=pHP3Q!=m`A8Af0b2bte>rP5_`~YSq@Z8)qo^EG*?u& zzz=UQt$jrWfQZha(X#Xx;cqv-Y+O#$1ZY=|0l1|y$8keFP;_W^+-;J82VK~vUKQQi zClmXY?YK%?rA}%TO#)lp2iCr+bZx6e!Yxg8E?MUkc>5N8k#Seug$&%%TpFrtb?H5h zLna+)x|%_W;Ac==s=Nnq% z2J=CZk7=DZX*dHh_GnwR2W-5dTdF(Y6HiPRcHj_+ZNh^g5VyK;INpD7@96d1hp&s< zmH~^sR?l>MMR)+))R|qR<=l0;Y8w_=5sLqQ7K)`(sjLiBSn3|yY}^CF80SYiuSZwU zn~ABTwSJhN7LUH~N4Z$;*Eo*O`tsr%`8G=3eYuBIcmE9kl}AklnKnu}Udq8K2T86k ze~NOI<2{_Kyq-q6hL>yLTmwmKzMMvxd&es{bMK<@+D4gmFSCv_>qz>}mvd--`D6yq zFMIP`Ay>dSLzp>pyWUZ{8rHM~$m(uyyqP`YqDgVTkJ z=O|tG(si7!Bk2oYo<(!z6A{mqy}1gWt01ZB%ULvAJl?{yMQ^r@XUj-h_T>eXubnh- zzUJjuaefs^^&r+I7VDCiDd9{BNo8NYgR=LJ8#sIaqKdM0FI&f1=BS@ePEYhBQY`+K zqvSm!{m|5uc(l$QyEv-zGdgxLu%ntCYYDW1z6n}o@J}o;v%t1Qxew6?gD(8aUZx`Z pm^wdE(hu=G-xoQ)fVj`E|N3H@7yI0G@-mL4{96XR{~t8)`wtsv$5j9T literal 0 HcmV?d00001 diff --git a/core/models.py b/core/models.py index 71a8362..ab07953 100644 --- a/core/models.py +++ b/core/models.py @@ -1,3 +1,25 @@ 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')}" \ No newline at end of file diff --git a/core/risk_engine.py b/core/risk_engine.py new file mode 100644 index 0000000..a72b082 --- /dev/null +++ b/core/risk_engine.py @@ -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 + } \ No newline at end of file diff --git a/core/templates/base.html b/core/templates/base.html index 1e7e5fb..7f66d6b 100644 --- a/core/templates/base.html +++ b/core/templates/base.html @@ -1,25 +1,85 @@ - - + - - {% block title %}Knowledge Base{% endblock %} - {% if project_description %} - - - - {% endif %} - {% if project_image_url %} - - - {% endif %} - {% load static %} - - {% block head %}{% endblock %} + + + {% block title %}ES Risk Dashboard{% endblock %} + + + + + + + + + + + + + + - - {% block content %}{% endblock %} +
+ {% block content %}{% endblock %} +
+ +
+
+

© 2026 RISKFLUX. MARKET SIMULATION ENGINE.

+

Quantitative risk estimation for educational purposes only.

+
+
+ + + + - - + \ No newline at end of file diff --git a/core/templates/core/index.html b/core/templates/core/index.html index faec813..c91c827 100644 --- a/core/templates/core/index.html +++ b/core/templates/core/index.html @@ -1,145 +1,284 @@ -{% extends "base.html" %} - -{% block title %}{{ project_name }}{% endblock %} - -{% block head %} - - - - -{% endblock %} +{% extends 'base.html' %} +{% load static %} {% block content %} -
-
-

Analyzing your requirements and generating your app…

-
- Loading… +
+ +
+

+ ES Risk Simulator +

+

S&P 500 Futures Intraday Scenarios & Regime Analysis

+
+ + {% if error %} +
+ +
Engine Error: {{ error }}
-

AppWizzy AI is collecting your requirements and applying the first changes.

-

This page will refresh automatically as the plan is implemented.

-

- Runtime: Django {{ django_version }} · Python {{ python_version }} - — UTC {{ current_time|date:"Y-m-d H:i:s" }} -

-
-
-
- Page updated: {{ current_time|date:"Y-m-d H:i:s" }} (UTC) -
+ {% endif %} + +
+ +
+
+
+
+
+ +

Analysis Control

+
+
+ {% csrf_token %} + +
+
+ + {% if latest %} +
+
+
+
+ + +
+
{{ latest.expected_low|floatformat:2 }}
+
Simulated Mean
+
+
+
+
+
+ + +
+
{{ latest.worst_case_5th|floatformat:2 }}
+
5th Percentile
+
+
+
+
+
+ + +
+
{{ latest.drawdown_prob|floatformat:2 }}%
+
Incident Prob
+
+
+
+ + +
+
+
+
+
+ + {{ latest.bias }} + +

Daily Bias

+ +
+

+ + Regime: {{ latest.regime|yesno:"High Volatility (Risk-Off),Low Volatility (Risk-On)" }} +

+
+
+
+
+
Target Profit
+
{{ latest.take_profit|floatformat:2 }}
+
+
+
Stop Loss
+
{{ latest.stop_loss|floatformat:2 }}
+
+
+
+
+
+ {% else %} +
+ +

No analysis available. Click the button to trigger the engine.

+
+ {% endif %} +
+
+ + +
+
+

+ Real-time Sentiment +

+ RSS ANALYSIS FEED +
+ +
+ {% if latest %} +
+ {% endif %} +
+
+ Bearish + Neutral + Bullish +
+ +
+ +
+
+

What is this?

+

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.

+
+
+

How to use?

+

Watch the Tail Risk (VaR) level. In high volatility regimes, price tends to test these boundaries. The Bias suggests a directional lean based on combined indicators.

+
+
+
+
+ + +
+
+
+
+ +

Engine History

+
+ +
+ {% for item in history %} +
+
+
+
{{ item.created_at|date:"M d, H:i" }}
+
+ {{ item.bias }} BIAS +
+
+
{{ item.expected_low|floatformat:1 }}
+
+
+ {% empty %} +
No history records found.
+ {% endfor %} +
+
+
+ +
+
+ +

System Integrity

+
+
+
+ Markov Chain: + ACTIVE +
+
+ Data Feed: + YFINANCE +
+
+ Bias Engine: + KALMAN-MOD +
+
+
+
+
+ + + {% endblock %} \ No newline at end of file diff --git a/core/urls.py b/core/urls.py index 6299e3d..9127173 100644 --- a/core/urls.py +++ b/core/urls.py @@ -1,7 +1,7 @@ from django.urls import path - -from .views import home +from . import views urlpatterns = [ - path("", home, name="home"), -] + path('', views.index, name='index'), + path('simulate/', views.run_simulation, name='run_simulation'), +] \ No newline at end of file diff --git a/core/views.py b/core/views.py index c9aed12..00c9987 100644 --- a/core/views.py +++ b/core/views.py @@ -1,25 +1,42 @@ -import os -import platform - -from django import get_version as django_version -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() +from django.shortcuts import render, redirect +from .models import SimulationResult +from .risk_engine import RiskEngine +import json +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 = { - "project_name": "New Style", - "agent_brand": agent_brand, - "django_version": django_version(), - "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", ""), + 'latest': latest, + 'history': history, + 'status': 'Ready' } - 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') \ No newline at end of file