diff --git a/OI_MeanReversion_Pro_XAUUSD_A.mq5 b/OI_MeanReversion_Pro_XAUUSD_A.mq5 index 9d0fd1a..979b95f 100644 Binary files a/OI_MeanReversion_Pro_XAUUSD_A.mq5 and b/OI_MeanReversion_Pro_XAUUSD_A.mq5 differ diff --git a/OI_OrderFlow_Absorption_XAUUSD.mq5 b/OI_OrderFlow_Absorption_XAUUSD.mq5 index 42c5caf..160b4f7 100644 --- a/OI_OrderFlow_Absorption_XAUUSD.mq5 +++ b/OI_OrderFlow_Absorption_XAUUSD.mq5 @@ -39,7 +39,7 @@ enum ENUM_OI_SOURCE { }; input group "=== OI & DELTA SETTINGS ===" -input ENUM_OI_SOURCE InpOISource = OI_SOURCE_MANUAL; +input ENUM_OI_SOURCE InpOISource = OI_SOURCE_CSV_FILE; input string InpOICsvPath = "\\Files\\oi_data.csv"; input double InpManualFuturePrice = 0.0; @@ -198,6 +198,14 @@ double CachedFuturePrice = -1; // -1 = not loaded, 0 = loaded but failed, string LoadedCSVPath = ""; // Path from which CSV was successfully loaded bool CSVLoadLogged = false; // Track if we've logged the result +double CSVDynamicCallStrike1 = 0.0; +double CSVDynamicCallStrike2 = 0.0; +double CSVDynamicCallStrike3 = 0.0; +double CSVDynamicPutStrike1 = 0.0; +double CSVDynamicPutStrike2 = 0.0; +double CSVDynamicPutStrike3 = 0.0; +bool CSVStrikesLoaded = false; + int OnInit() { Trade.SetExpertMagicNumber(InpMagicNumber); Trade.SetDeviationInPoints(InpMaxSlippage); @@ -206,16 +214,21 @@ int OnInit() { SymbolInfo.Name(_Symbol); SymbolInfo.RefreshRates(); - DynamicFuturePrice = InpManualFuturePrice; - DynamicCallStrike1 = InpCallStrike1; - DynamicCallStrike2 = InpCallStrike2; - DynamicCallStrike3 = InpCallStrike3; - DynamicPutStrike1 = InpPutStrike1; - DynamicPutStrike2 = InpPutStrike2; - DynamicPutStrike3 = InpPutStrike3; - - InitializeOILevels(); - InitializeKeyLevels(); + DynamicFuturePrice = InpManualFuturePrice; + DynamicCallStrike1 = InpCallStrike1; + DynamicCallStrike2 = InpCallStrike2; + DynamicCallStrike3 = InpCallStrike3; + DynamicPutStrike1 = InpPutStrike1; + DynamicPutStrike2 = InpPutStrike2; + DynamicPutStrike3 = InpPutStrike3; + + InitializeOILevels(); + InitializeKeyLevels(); + + if(InpOISource == OI_SOURCE_CSV_FILE) { + LoadFuturePriceFromCSV(); + ApplyCSVStrikeLevels(); + } if(!InitializeIndicators()) { Print("Error initializing indicators"); @@ -436,7 +449,11 @@ void UpdateMarketData() { SpotPrice = SymbolInfo.Bid(); SymbolInfo.RefreshRates(); - FuturePrice = LoadFuturePriceFromCSV(); + if(InpOISource == OI_SOURCE_CSV_FILE) { + FuturePrice = LoadFuturePriceFromCSV(); + } else { + FuturePrice = 0; + } } bool IsPriceNearPutStrike() { @@ -985,84 +1002,179 @@ bool InitializeIndicators() { } double LoadFuturePriceFromCSV() { - if(CachedFuturePrice >= 0) { - return CachedFuturePrice; - } + if(CachedFuturePrice >= 0 && CachedFuturePrice != 0) { + return CachedFuturePrice; + } - string paths[]; - int pathCount = 0; + string paths[]; + int pathCount = 0; - ArrayResize(paths, 5); - paths[pathCount++] = InpOICsvPath; - paths[pathCount++] = "oi_data.csv"; - paths[pathCount++] = "\\Files\\oi_data.csv"; - paths[pathCount++] = "..\\oi_scraper\\oi_data.csv"; - paths[pathCount++] = "../oi_scraper/oi_data.csv"; + ArrayResize(paths, 5); + paths[pathCount++] = InpOICsvPath; + paths[pathCount++] = "oi_data.csv"; + paths[pathCount++] = "\\Files\\oi_data.csv"; + paths[pathCount++] = "..\\oi_scraper\\oi_data.csv"; + paths[pathCount++] = "../oi_scraper/oi_data.csv"; - int filehandle = INVALID_HANDLE; - string foundPath = ""; + int filehandle = INVALID_HANDLE; + string foundPath = ""; - for(int i = 0; i < pathCount; i++) { - filehandle = FileOpen(paths[i], FILE_READ | FILE_CSV, ','); - if(filehandle != INVALID_HANDLE) { - foundPath = paths[i]; - break; - } - } + for(int i = 0; i < pathCount; i++) { + if(!CSVLoadLogged) { + Print("Trying CSV path: ", paths[i]); + } + filehandle = FileOpen(paths[i], FILE_READ | FILE_CSV | FILE_ANSI, ','); + if(filehandle != INVALID_HANDLE) { + foundPath = paths[i]; + if(!CSVLoadLogged) { + Print("Found CSV file at: ", foundPath); + } + break; + } + } - if(filehandle == INVALID_HANDLE) { - if(!CSVLoadLogged) { - Print("CSV ERROR: File not found. Searched paths:"); - for(int i = 0; i < pathCount; i++) { - Print(" - ", paths[i]); - } - CSVLoadLogged = true; - } - CachedFuturePrice = 0; - return 0.0; - } + if(filehandle == INVALID_HANDLE) { + if(!CSVLoadLogged) { + Print("CSV ERROR: File not found. Searched paths:"); + for(int i = 0; i < pathCount; i++) { + Print(" - ", paths[i]); + } + CSVLoadLogged = true; + } + CachedFuturePrice = 0; + return 0.0; + } - double futurePrice = 0.0; - int dataLineCount = 0; + double futurePrice = 0.0; + double callStrikes[]; + double putStrikes[]; + int callCount = 0; + int putCount = 0; + bool inPriceSection = false; + int dataLineCount = 0; - while(!FileIsEnding(filehandle)) { - string line = FileReadString(filehandle); - dataLineCount++; + while(!FileIsEnding(filehandle)) { + string line = FileReadString(filehandle); + dataLineCount++; - if(line == "") continue; + if(line == "") { + inPriceSection = true; + continue; + } - string parts[]; - int split = StringSplit(line, ',', parts); + if(dataLineCount == 1 && StringGetCharacter(line, 0) == 0xFEFF) { + line = StringSubstr(line, 1); + if(line == "") { + inPriceSection = true; + continue; + } + } - if(split >= 2) { - double price = StringToDouble(parts[1]); - if(price > 0) { - futurePrice = price; - break; - } - } - } + if(StringFind(line, "Type") >= 0 || StringFind(line, "Strike") >= 0 || StringFind(line, "OI") >= 0) { + continue; + } - FileClose(filehandle); + if(line == "[Price]" || inPriceSection) { + inPriceSection = true; + string parts[]; + int split = StringSplit(line, ',', parts); + + if(split >= 2 && parts[0] == "FuturePrice") { + string priceStr = parts[1]; + while(StringLen(priceStr) > 0 && (StringGetCharacter(priceStr, 0) == 32 || StringGetCharacter(priceStr, 0) == 9)) { + priceStr = StringSubstr(priceStr, 1); + } + while(StringLen(priceStr) > 0 && (StringGetCharacter(priceStr, StringLen(priceStr)-1) == 32 || StringGetCharacter(priceStr, StringLen(priceStr)-1) == 9)) { + priceStr = StringSubstr(priceStr, 0, StringLen(priceStr)-1); + } + futurePrice = StringToDouble(priceStr); + if(!CSVLoadLogged) { + Print("DEBUG: Parsed FuturePrice: ", futurePrice); + } + } + continue; + } - if(futurePrice > 0) { - CachedFuturePrice = futurePrice; - LoadedCSVPath = foundPath; - if(!CSVLoadLogged) { - Print("CSV SUCCESS: FuturePrice=", futurePrice, " loaded from ", foundPath); - CSVLoadLogged = true; - } - } else { - if(!CSVLoadLogged) { - Print("CSV ERROR: No valid price found in ", foundPath); - Print(" - File exists but contains no parseable price data"); - CSVLoadLogged = true; - } - CachedFuturePrice = 0; - } + string parts[]; + int split = StringSplit(line, ',', parts); - return CachedFuturePrice; -} + if(split >= 3) { + string typeStr = parts[0]; + string strikeStr = parts[1]; + string oiStr = parts[2]; + + while(StringLen(strikeStr) > 0 && (StringGetCharacter(strikeStr, 0) == 32 || StringGetCharacter(strikeStr, 0) == 9)) { + strikeStr = StringSubstr(strikeStr, 1); + } + while(StringLen(strikeStr) > 0 && (StringGetCharacter(strikeStr, StringLen(strikeStr)-1) == 32 || StringGetCharacter(strikeStr, StringLen(strikeStr)-1) == 9)) { + strikeStr = StringSubstr(strikeStr, 0, StringLen(strikeStr)-1); + } + + double strike = StringToDouble(strikeStr); + if(strike <= 0) continue; + + if(typeStr == "CALL") { + ArrayResize(callStrikes, callCount + 1); + callStrikes[callCount] = strike; + callCount++; + } else if(typeStr == "PUT") { + ArrayResize(putStrikes, putCount + 1); + putStrikes[putCount] = strike; + putCount++; + } + } + } + + FileClose(filehandle); + + if(callCount > 0) { + ArraySort(callStrikes); + if(callCount >= 1) CSVDynamicCallStrike1 = callStrikes[callCount-1]; + if(callCount >= 2) CSVDynamicCallStrike2 = callStrikes[callCount-2]; + if(callCount >= 3) CSVDynamicCallStrike3 = callStrikes[callCount-3]; + } + + if(putCount > 0) { + ArraySort(putStrikes); + if(putCount >= 1) CSVDynamicPutStrike1 = putStrikes[putCount-1]; + if(putCount >= 2) CSVDynamicPutStrike2 = putStrikes[putCount-2]; + if(putCount >= 3) CSVDynamicPutStrike3 = putStrikes[putCount-3]; + } + + if(futurePrice > 0) { + CachedFuturePrice = futurePrice; + LoadedCSVPath = foundPath; + CSVStrikesLoaded = true; + if(!CSVLoadLogged) { + Print("CSV SUCCESS: FuturePrice=", futurePrice, ", CALL=[", CSVDynamicCallStrike1, ",", CSVDynamicCallStrike2, ",", CSVDynamicCallStrike3, "], PUT=[", CSVDynamicPutStrike1, ",", CSVDynamicPutStrike2, ",", CSVDynamicPutStrike3, "] loaded from ", foundPath); + CSVLoadLogged = true; + } + } else { + if(!CSVLoadLogged) { + Print("CSV ERROR: No valid price found in ", foundPath); + Print(" - File exists but contains no parseable price data"); + Print(" - Total lines read: ", dataLineCount); + CSVLoadLogged = true; + } + CachedFuturePrice = 0; + } + + return CachedFuturePrice; + } + + void ApplyCSVStrikeLevels() { + if(!CSVStrikesLoaded) return; + + if(DynamicCallStrike1 == 0 && CSVDynamicCallStrike1 > 0) DynamicCallStrike1 = CSVDynamicCallStrike1; + if(DynamicCallStrike2 == 0 && CSVDynamicCallStrike2 > 0) DynamicCallStrike2 = CSVDynamicCallStrike2; + if(DynamicCallStrike3 == 0 && CSVDynamicCallStrike3 > 0) DynamicCallStrike3 = CSVDynamicCallStrike3; + if(DynamicPutStrike1 == 0 && CSVDynamicPutStrike1 > 0) DynamicPutStrike1 = CSVDynamicPutStrike1; + if(DynamicPutStrike2 == 0 && CSVDynamicPutStrike2 > 0) DynamicPutStrike2 = CSVDynamicPutStrike2; + if(DynamicPutStrike3 == 0 && CSVDynamicPutStrike3 > 0) DynamicPutStrike3 = CSVDynamicPutStrike3; + + InitializeOILevels(); + InitializeKeyLevels(); + } void CheckExistingPositions() { for(int i = 0; i < PositionsTotal(); i++) { @@ -1299,11 +1411,36 @@ void HandleControlPanelClick(string name) { } void UpdateInputValues() { - DynamicFuturePrice = StringToDouble(ObjectGetString(chart_id, "CP_FuturePrice", OBJPROP_TEXT)); - DynamicCallStrike1 = StringToDouble(ObjectGetString(chart_id, "CP_CallStrike1", OBJPROP_TEXT)); - DynamicCallStrike2 = StringToDouble(ObjectGetString(chart_id, "CP_CallStrike2", OBJPROP_TEXT)); - DynamicCallStrike3 = StringToDouble(ObjectGetString(chart_id, "CP_CallStrike3", OBJPROP_TEXT)); - DynamicPutStrike1 = StringToDouble(ObjectGetString(chart_id, "CP_PutStrike1", OBJPROP_TEXT)); - DynamicPutStrike2 = StringToDouble(ObjectGetString(chart_id, "CP_PutStrike2", OBJPROP_TEXT)); - DynamicPutStrike3 = StringToDouble(ObjectGetString(chart_id, "CP_PutStrike3", OBJPROP_TEXT)); -} + string value; + + if(ObjectGetString(chart_id, "CP_FuturePrice", OBJPROP_TEXT, 0, value)) { + DynamicFuturePrice = StringToDouble(value); + } + + if(ObjectGetString(chart_id, "CP_CallStrike1", OBJPROP_TEXT, 0, value)) { + DynamicCallStrike1 = StringToDouble(value); + } + if(ObjectGetString(chart_id, "CP_CallStrike2", OBJPROP_TEXT, 0, value)) { + DynamicCallStrike2 = StringToDouble(value); + } + if(ObjectGetString(chart_id, "CP_CallStrike3", OBJPROP_TEXT, 0, value)) { + DynamicCallStrike3 = StringToDouble(value); + } + if(ObjectGetString(chart_id, "CP_PutStrike1", OBJPROP_TEXT, 0, value)) { + DynamicPutStrike1 = StringToDouble(value); + } + if(ObjectGetString(chart_id, "CP_PutStrike2", OBJPROP_TEXT, 0, value)) { + DynamicPutStrike2 = StringToDouble(value); + } + if(ObjectGetString(chart_id, "CP_PutStrike3", OBJPROP_TEXT, 0, value)) { + DynamicPutStrike3 = StringToDouble(value); + } + + InitializeOILevels(); + InitializeKeyLevels(); + + if(InpOISource == OI_SOURCE_CSV_FILE) { + LoadFuturePriceFromCSV(); + ApplyCSVStrikeLevels(); + } + } \ No newline at end of file diff --git a/oi_scraper/main.py b/oi_scraper/main.py index fe895d3..2bc346e 100644 --- a/oi_scraper/main.py +++ b/oi_scraper/main.py @@ -290,9 +290,22 @@ def scrape_investing_gold_price(page): def export_to_csv(df, future_price=0.0): output_path = CSV_OUTPUT_PATH - with open(output_path, "w") as f: - f.write("date,future_price\n") - f.write(f"{datetime.now().strftime('%Y-%m-%d')},{future_price}\n") + with open(output_path, "w", encoding="utf-8") as f: + f.write("Type,Strike,OI\n") + + call_df = df[df["Type"] == "CALL"] if len(df) > 0 else pd.DataFrame() + put_df = df[df["Type"] == "PUT"] if len(df) > 0 else pd.DataFrame() + + if len(call_df) > 0: + for _, row in call_df.iterrows(): + f.write(f"CALL,{row['Strike']:.1f},{row['OI']}\n") + + if len(put_df) > 0: + for _, row in put_df.iterrows(): + f.write(f"PUT,{row['Strike']:.1f},{row['OI']}\n") + + f.write("\n[Price]\n") + f.write(f"FuturePrice,{future_price}\n") logger.info(f"Exported OI data and price to {output_path}")