diff --git a/WebServer/AIPython/aipredictor.py b/WebServer/AIPython/aipredictor.py
index 70af3a45..566ced2a 100644
--- a/WebServer/AIPython/aipredictor.py
+++ b/WebServer/AIPython/aipredictor.py
@@ -1,3 +1,4 @@
+from datetime import datetime, timedelta
import os
import sys
import joblib
@@ -13,13 +14,29 @@ def Predict():
# Get the Symbol from ARGV
Symbol = sys.argv[1]
+ # get the number of days ago to run the simulation for
+ DaysBack = int(sys.argv[2])
+
+ print(f"Days back: {DaysBack}")
+
+ # calculate the time offsets
+ end_date = datetime.now() - timedelta(days=DaysBack)
+ start_date = end_date - timedelta(days=70)
+
+ # convert to string formats
+ start_str = start_date.strftime('%Y-%m-%d')
+ end_str = end_date.strftime('%Y-%m-%d')
+
+ print(f"Start Date: {start_str}")
+ print(f"End Date: {end_str}")
+
# Define paths (consistent with your previous script)
SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
DATA_DIR = os.path.join(SCRIPT_DIR, "data")
MODEL_PATH = os.path.join(DATA_DIR, "model.keras")
# Pull 1 month of current data to make prediction against | for volatility 20
- df = yf.download(Symbol, period="2mo", auto_adjust=True)
+ df = yf.download(Symbol, start=start_str, end=end_str, auto_adjust=True, progress=False)
if not df.empty:
# Remove the horizontal ticker column
df.columns = df.columns.get_level_values(0)
diff --git a/WebServer/AIPython/features.py b/WebServer/AIPython/features.py
index 981ecee7..c08d8169 100644
--- a/WebServer/AIPython/features.py
+++ b/WebServer/AIPython/features.py
@@ -78,10 +78,11 @@ def MakeFeatures(df):
df.drop(col, axis=1, inplace=True)
# Drop rows with null values
- df.dropna(inplace=True)
+ feature_columns = [col for col in df.columns if col != 'Target_Close'] # Dont drop any Target_Close as we need this data for predictions
+ df.dropna(subset=feature_columns, inplace=True)
# Replace Infinity with 0 -> This fixes the AI mental breakdown
- df = df.replace([np.inf, -np.inf], 0)
+ df.replace([np.inf, -np.inf], 0, inplace=True)
# Replace Infinity with 0 -> This fixes the AI mental breakdown
df['Volume_Chg'] = df['Volume_Chg'].replace([np.inf, -np.inf], 0)
diff --git a/WebServer/Components/Pages/Home.razor b/WebServer/Components/Pages/Home.razor
index 5b8e0b6f..fb58464b 100644
--- a/WebServer/Components/Pages/Home.razor
+++ b/WebServer/Components/Pages/Home.razor
@@ -1,5 +1,6 @@
@page "/"
@using Controllers.Payment
+@using Controllers.ProjectTest
@using Microsoft.Extensions.FileSystemGlobbing.Internal.PathSegments
@rendermode InteractiveServer
@@ -46,6 +47,11 @@
+
+
+
+ @TestResults
+
@resultError
@@ -195,4 +201,13 @@
string dbPrefix = $"[{userName.ToLower()}]:";
dbDriver.Set(dbPrefix + "watched", JsonConvert.SerializeObject(Session.TrackedStocks) );
}
+
+
+ string TestResults = "";
+ async Task RunTest(){
+ D683_Project_Test tests = new D683_Project_Test(aiModule);
+ float score = await tests.Simulate();
+ TestResults = score.ToString();
+ }
+
}
\ No newline at end of file
diff --git a/WebServer/Controllers/Automation.cs b/WebServer/Controllers/Automation.cs
index 3c8700aa..97676e34 100644
--- a/WebServer/Controllers/Automation.cs
+++ b/WebServer/Controllers/Automation.cs
@@ -17,14 +17,17 @@ namespace Controllers.Automation {
_paymentProcessor = PaymentProcessor;
}
- public void GlobalPredictAI() {
+ public void GlobalPredictAI(int DaysBefore = 0, bool testmode = false) {
// Start this process on a background thread so its non-blocking
Task thread = new Task(() => {
// Load the userlist
- List? UserList = JsonConvert.DeserializeObject>(_dbDriver.Get("Users"));
- List VerifiedUserList = UserList != null ? UserList : new List();
+ List VerifiedUserList = new List(){ "TESTMODE" };
+ if (!testmode) {
+ List? UserList = JsonConvert.DeserializeObject>(_dbDriver.Get("Users"));
+ VerifiedUserList = UserList != null ? UserList : new List();
+ }
// Process each request at the same time for speed improvement
Parallel.ForEach(VerifiedUserList, async (username) => {
@@ -40,7 +43,7 @@ namespace Controllers.Automation {
// Predict the trend on a new thread
Task thread = new Task(() => {
- (string, float)Result = _aiModule.PredictAI(cur.Symbol);
+ (string, float)Result = _aiModule.PredictAI(cur.Symbol, DaysBefore);
// If error log it
if (!string.IsNullOrEmpty(Result.Item1)){
diff --git a/WebServer/Controllers/ProjectTest.cs b/WebServer/Controllers/ProjectTest.cs
new file mode 100644
index 00000000..2846f002
--- /dev/null
+++ b/WebServer/Controllers/ProjectTest.cs
@@ -0,0 +1,111 @@
+using Controllers.PythonInterop;
+using Entities;
+using Microsoft.AspNetCore.Razor.TagHelpers;
+
+namespace Controllers.ProjectTest {
+
+ public class D683_Project_Test {
+
+ // TESTING Starting Money
+ float Money = 1000;
+
+ // TESTING WATCH STOCK LIST
+ List TrackedStocks = new List() {
+ new Stock(){ Symbol="NVDA" },
+ new Stock(){ Symbol="INTL" },
+ new Stock(){ Symbol="AAPL" },
+ new Stock(){ Symbol="SHOP" },
+ new Stock(){ Symbol="PANW" },
+ new Stock(){ Symbol="BBBY" },
+ new Stock(){ Symbol="REAL" },
+ new Stock(){ Symbol="W" },
+ new Stock(){ Symbol="ROKU" },
+ new Stock(){ Symbol="FUN" }
+ };
+
+ // TESTING STOCK HISTORY
+ List StockHistory = new List();
+
+ AIModule _aiModule;
+ public D683_Project_Test( AIModule aiModule ) {
+ _aiModule = aiModule;
+ }
+
+ public async Task Simulate() {
+ float StartingMoney = Money;
+ // Run once for each day 30 days straight
+ for (int i=30; i>=0; i--) {
+
+ // Go through each watched stock and find the highest prediction
+ List threadpool = new List();
+ foreach(Stock cur in TrackedStocks) {
+
+ // Predict the trend on a new thread
+ Task thread = new Task(async () => {
+ (string, float)Result = _aiModule.PredictAI(cur.Symbol, i);
+
+ // If error log it
+ if (!string.IsNullOrEmpty(Result.Item1)){
+ Console.WriteLine(Result.Item1);
+ }
+
+ // Write the score to the users tracked stocks
+ cur.Score = Result.Item2;
+ });
+ thread.Start();
+ threadpool.Add(thread);
+ }
+
+ // Wait for all processes to finish
+ await Task.WhenAll( threadpool );
+
+ // Get the highest ranked
+ Stock HighestRanking = new Stock(){ Symbol="NVDA", Score = -400 }; // Just a placeholder incase an empty list comes through there is a fallback
+ foreach(Stock cur in TrackedStocks) {
+ if (HighestRanking.Score < cur.Score) {
+ HighestRanking = cur;
+ }
+ }
+
+ // Sell all stocks
+ float totalSale = 0;
+ foreach(PurchasedStock cur in StockHistory) {
+ if (cur.Sold == false) {
+ // Get sell price
+ float sellPrice = cur.Quantity * _aiModule.GetCurrentPrice( cur.Symbol );
+ // Add up the total sale
+ totalSale += sellPrice;
+ // Mark as sold
+ cur.Sold = true;
+ }
+ }
+ Money += totalSale;
+
+ // Dont buy anything on the last run
+ if (i != 0) {
+
+ // Buy predicted stock
+ float stockPrice = _aiModule.GetCurrentPrice( HighestRanking.Symbol );
+
+ // Get max stocks user can purchase [ int cast truncates the decimal ]
+ int MaxQty = (int)( Money / stockPrice );
+
+ // Add the stock
+ StockHistory.Add( new PurchasedStock(){
+ Symbol = HighestRanking.Symbol.ToUpper(),
+ PurchasePrice = stockPrice,
+ Quantity = MaxQty,
+ } );
+ Money = Money - ( stockPrice * MaxQty );
+ }
+ }
+
+ // Return a score [Bigger than 0 is money earned] or [Less than 0 is money lost]
+ return Money - StartingMoney;
+ }
+
+
+
+
+ }
+}
\ No newline at end of file
diff --git a/WebServer/Controllers/PythonInterop.cs b/WebServer/Controllers/PythonInterop.cs
index fed83587..d2290daf 100644
--- a/WebServer/Controllers/PythonInterop.cs
+++ b/WebServer/Controllers/PythonInterop.cs
@@ -27,8 +27,8 @@ namespace Controllers.PythonInterop {
}
// Return ( Error, Signal )
- public (string, float) PredictAI(string StockSymbol) {
- (bool, string) Success = PyProcess.RunPythonProcess(_PyPath, _ExecPath + "/aipredictor.py", returns: true, PyArgs: StockSymbol);
+ public (string, float) PredictAI(string StockSymbol, int DataEndDaysAgo = 0) {
+ (bool, string) Success = PyProcess.RunPythonProcess(_PyPath, _ExecPath + "/aipredictor.py", returns: true, PyArgs: $"{StockSymbol} {DataEndDaysAgo}");
if (!Success.Item1) {
return (Success.Item2, 0);
} else {