From 143f2567c7bca865400b7b207cc591f02a9c1b7b Mon Sep 17 00:00:00 2001 From: Kunthawat Greethong Date: Thu, 8 Jan 2026 12:30:31 +0700 Subject: [PATCH] update code and fix bugs --- OI_MeanReversion_Pro_XAUUSD_A.mq5 | Bin 166768 -> 160974 bytes OI_OrderFlow_Absorption_XAUUSD.mq5 | 307 +++++++++++++++++++++-------- oi_scraper/main.py | 19 +- 3 files changed, 238 insertions(+), 88 deletions(-) diff --git a/OI_MeanReversion_Pro_XAUUSD_A.mq5 b/OI_MeanReversion_Pro_XAUUSD_A.mq5 index 9d0fd1ae118436b142749855308d547381b74b20..979b95f03cd30540b4596afda1183a3d04c11759 100644 GIT binary patch delta 22814 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 Yo#&A}7T#mD()tT1)Kh)dDFgfe1Jv@ossI20 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}")