update EA
This commit is contained in:
@@ -38,6 +38,7 @@ enum ENUM_OI_SOURCE {
|
|||||||
};
|
};
|
||||||
input ENUM_OI_SOURCE InpOISource = OI_SOURCE_MANUAL;
|
input ENUM_OI_SOURCE InpOISource = OI_SOURCE_MANUAL;
|
||||||
input string InpOICsvPath = "\\Files\\oi_data.csv"; // Path to CSV file
|
input string InpOICsvPath = "\\Files\\oi_data.csv"; // Path to CSV file
|
||||||
|
input int InpCSVReloadInterval = 60; // CSV reload interval (minutes, 0=disabled)
|
||||||
input double InpManualFuturePrice = 0.0; // Manual future price input
|
input double InpManualFuturePrice = 0.0; // Manual future price input
|
||||||
|
|
||||||
// OI Levels (Manual Input - สามารถใส่ได้ถึง 3 ระดับ)
|
// OI Levels (Manual Input - สามารถใส่ได้ถึง 3 ระดับ)
|
||||||
@@ -170,6 +171,12 @@ bool NewsBlockActive = false;
|
|||||||
datetime NewsBlockStart = 0;
|
datetime NewsBlockStart = 0;
|
||||||
datetime NewsBlockEnd = 0;
|
datetime NewsBlockEnd = 0;
|
||||||
|
|
||||||
|
// CSV Cache Variables
|
||||||
|
double CachedFuturePrice = -1;
|
||||||
|
string LoadedCSVPath = "";
|
||||||
|
bool CSVLoadLogged = false;
|
||||||
|
datetime LastCSVReloadTime = 0;
|
||||||
|
|
||||||
//=== NEW: Control Panel Variables ===
|
//=== NEW: Control Panel Variables ===
|
||||||
// Control Panel Position - Moved below dashboard
|
// Control Panel Position - Moved below dashboard
|
||||||
int ControlPanelX = 10;
|
int ControlPanelX = 10;
|
||||||
@@ -357,21 +364,31 @@ void OnTick()
|
|||||||
//+------------------------------------------------------------------+
|
//+------------------------------------------------------------------+
|
||||||
void OnTimer()
|
void OnTimer()
|
||||||
{
|
{
|
||||||
//--- Update dashboard periodically
|
//--- Update dashboard periodically
|
||||||
if(InpEnableDashboard)
|
if(InpEnableDashboard)
|
||||||
{
|
{
|
||||||
UpdateDashboard();
|
UpdateDashboard();
|
||||||
UpdateControlPanel();
|
UpdateControlPanel();
|
||||||
}
|
}
|
||||||
|
|
||||||
//--- Check news events
|
//--- Check news events
|
||||||
if(InpAvoidHighImpactNews)
|
if(InpAvoidHighImpactNews)
|
||||||
{
|
{
|
||||||
CheckNewsEvents();
|
CheckNewsEvents();
|
||||||
}
|
}
|
||||||
|
|
||||||
//--- Reset daily statistics if new day
|
//--- Reset daily statistics if new day
|
||||||
CheckDailyReset();
|
CheckDailyReset();
|
||||||
|
|
||||||
|
//--- CSV reload check
|
||||||
|
if(InpOISource == OI_SOURCE_CSV_FILE && InpCSVReloadInterval > 0) {
|
||||||
|
if(TimeCurrent() - LastCSVReloadTime >= InpCSVReloadInterval * 60) {
|
||||||
|
Print("CSV Reload: Scheduled reload triggered");
|
||||||
|
LastCSVReloadTime = TimeCurrent();
|
||||||
|
CachedFuturePrice = -1;
|
||||||
|
LoadOIFromCSV();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//+------------------------------------------------------------------+
|
//+------------------------------------------------------------------+
|
||||||
@@ -1094,64 +1111,91 @@ void InitializeOILevels()
|
|||||||
//+------------------------------------------------------------------+
|
//+------------------------------------------------------------------+
|
||||||
void LoadOIFromCSV()
|
void LoadOIFromCSV()
|
||||||
{
|
{
|
||||||
string filename = InpOICsvPath;
|
string filename = InpOICsvPath;
|
||||||
int filehandle = FileOpen(filename, FILE_READ|FILE_CSV|FILE_ANSI, ',');
|
int filehandle = FileOpen(filename, FILE_READ|FILE_CSV|FILE_ANSI, ',');
|
||||||
|
|
||||||
if(filehandle == INVALID_HANDLE)
|
if(filehandle == INVALID_HANDLE)
|
||||||
{
|
{
|
||||||
Print("Error opening CSV file: ", filename);
|
Print("Error opening CSV file: ", filename);
|
||||||
// Fall back to manual levels
|
InitializeOILevels();
|
||||||
InitializeOILevels();
|
return;
|
||||||
return;
|
}
|
||||||
}
|
|
||||||
|
int callIndex = 0;
|
||||||
// Skip header if exists
|
int putIndex = 0;
|
||||||
FileReadString(filehandle);
|
double futurePrice = 0.0;
|
||||||
|
bool isFirstLine = true;
|
||||||
int callIndex = 0;
|
|
||||||
int putIndex = 0;
|
while(!FileIsEnding(filehandle) && (callIndex < 3 || putIndex < 3))
|
||||||
|
{
|
||||||
while(!FileIsEnding(filehandle) && (callIndex < 3 || putIndex < 3))
|
string row = FileReadString(filehandle);
|
||||||
{
|
|
||||||
string row = FileReadString(filehandle);
|
if(isFirstLine) {
|
||||||
string data[];
|
isFirstLine = false;
|
||||||
int count = StringSplit(row, ',', data);
|
if(StringFind(row, "Type") >= 0 || StringFind(row, "Strike") >= 0 || StringFind(row, "OI") >= 0) {
|
||||||
|
continue;
|
||||||
if(count >= 3)
|
}
|
||||||
{
|
}
|
||||||
string type = data[0];
|
|
||||||
double strike = StringToDouble(data[1]);
|
string data[];
|
||||||
int oi = (int)StringToInteger(data[2]);
|
int count = StringSplit(row, ',', data);
|
||||||
|
|
||||||
if(type == "CALL" && callIndex < 3)
|
if(count >= 3)
|
||||||
{
|
{
|
||||||
CallLevels[callIndex] = strike;
|
string type = data[0];
|
||||||
CallOI[callIndex] = oi;
|
double strike = StringToDouble(data[1]);
|
||||||
callIndex++;
|
int oi = (int)StringToInteger(data[2]);
|
||||||
}
|
|
||||||
else if(type == "PUT" && putIndex < 3)
|
if(StringFind(type, "Future") >= 0)
|
||||||
{
|
{
|
||||||
PutLevels[putIndex] = strike;
|
futurePrice = strike;
|
||||||
PutOI[putIndex] = oi;
|
if(!CSVLoadLogged) {
|
||||||
putIndex++;
|
Print("DEBUG: Parsed Future price: ", futurePrice);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
else if(type == "CALL" && callIndex < 3)
|
||||||
|
{
|
||||||
FileClose(filehandle);
|
CallLevels[callIndex] = strike;
|
||||||
|
CallOI[callIndex] = oi;
|
||||||
// Fill any missing levels with zeros
|
callIndex++;
|
||||||
for(int i = callIndex; i < 3; i++)
|
}
|
||||||
{
|
else if(type == "PUT" && putIndex < 3)
|
||||||
CallLevels[i] = 0;
|
{
|
||||||
CallOI[i] = 0;
|
PutLevels[putIndex] = strike;
|
||||||
}
|
PutOI[putIndex] = oi;
|
||||||
|
putIndex++;
|
||||||
for(int i = putIndex; i < 3; i++)
|
}
|
||||||
{
|
}
|
||||||
PutLevels[i] = 0;
|
}
|
||||||
PutOI[i] = 0;
|
|
||||||
}
|
FileClose(filehandle);
|
||||||
|
|
||||||
|
for(int i = callIndex; i < 3; i++)
|
||||||
|
{
|
||||||
|
CallLevels[i] = 0;
|
||||||
|
CallOI[i] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(int i = putIndex; i < 3; i++)
|
||||||
|
{
|
||||||
|
PutLevels[i] = 0;
|
||||||
|
PutOI[i] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(futurePrice > 0) {
|
||||||
|
CachedFuturePrice = futurePrice;
|
||||||
|
DynamicFuturePrice = futurePrice;
|
||||||
|
FuturePrice = futurePrice;
|
||||||
|
LoadedCSVPath = filename;
|
||||||
|
CSVLoadLogged = true;
|
||||||
|
Print("CSV SUCCESS: FuturePrice=", futurePrice, ", CALL=[", CallLevels[0], ",", CallLevels[1], ",", CallLevels[2], "], PUT=[", PutLevels[0], ",", PutLevels[1], ",", PutLevels[2], "] loaded from ", filename);
|
||||||
|
} else {
|
||||||
|
if(!CSVLoadLogged) {
|
||||||
|
Print("CSV ERROR: No valid price found in ", filename);
|
||||||
|
CSVLoadLogged = true;
|
||||||
|
}
|
||||||
|
CachedFuturePrice = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//+------------------------------------------------------------------+
|
//+------------------------------------------------------------------+
|
||||||
@@ -1214,32 +1258,36 @@ bool InitializeIndicators()
|
|||||||
//+------------------------------------------------------------------+
|
//+------------------------------------------------------------------+
|
||||||
bool UpdateMarketData()
|
bool UpdateMarketData()
|
||||||
{
|
{
|
||||||
// Get current prices
|
// Get current prices
|
||||||
SpotPrice = SymbolInfo.Bid();
|
SpotPrice = SymbolInfo.Bid();
|
||||||
SymbolInfo.RefreshRates();
|
SymbolInfo.RefreshRates();
|
||||||
|
|
||||||
// Get future price (manual or from symbol)
|
// Get future price (CSV cache, manual or from symbol)
|
||||||
if(DynamicFuturePrice > 0)
|
if(CachedFuturePrice > 0)
|
||||||
{
|
{
|
||||||
FuturePrice = DynamicFuturePrice;
|
FuturePrice = CachedFuturePrice;
|
||||||
}
|
}
|
||||||
else if(InpManualFuturePrice > 0)
|
else if(DynamicFuturePrice > 0)
|
||||||
{
|
{
|
||||||
FuturePrice = InpManualFuturePrice;
|
FuturePrice = DynamicFuturePrice;
|
||||||
}
|
}
|
||||||
else
|
else if(InpManualFuturePrice > 0)
|
||||||
{
|
{
|
||||||
// In real implementation, you might get this from a different symbol
|
FuturePrice = InpManualFuturePrice;
|
||||||
// For now, use spot price with a small offset
|
}
|
||||||
FuturePrice = SpotPrice;
|
else
|
||||||
}
|
{
|
||||||
|
// In real implementation, you might get this from a different symbol
|
||||||
// Calculate Delta
|
// For now, use spot price with a small offset
|
||||||
double previousDelta = DeltaPrice;
|
FuturePrice = SpotPrice;
|
||||||
DeltaPrice = FuturePrice - SpotPrice;
|
}
|
||||||
|
|
||||||
// Update Delta EMA
|
// Calculate Delta
|
||||||
UpdateDeltaEMA();
|
double previousDelta = DeltaPrice;
|
||||||
|
DeltaPrice = FuturePrice - SpotPrice;
|
||||||
|
|
||||||
|
// Update Delta EMA
|
||||||
|
UpdateDeltaEMA();
|
||||||
|
|
||||||
// Calculate Deviation
|
// Calculate Deviation
|
||||||
DeltaDeviation = DeltaPrice - DeltaEMA;
|
DeltaDeviation = DeltaPrice - DeltaEMA;
|
||||||
|
|||||||
@@ -98,6 +98,7 @@ input int InpTrailingStepPoints = 50;
|
|||||||
input bool InpUseSoftStopLoss = true;
|
input bool InpUseSoftStopLoss = true;
|
||||||
input bool InpUseAutoRecovery = true;
|
input bool InpUseAutoRecovery = true;
|
||||||
input bool InpEnableDashboard = true;
|
input bool InpEnableDashboard = true;
|
||||||
|
input int InpCSVReloadInterval = 60;
|
||||||
|
|
||||||
CTrade Trade;
|
CTrade Trade;
|
||||||
CSymbolInfo SymbolInfo;
|
CSymbolInfo SymbolInfo;
|
||||||
@@ -199,6 +200,7 @@ double LastPrice = 0.0;
|
|||||||
double CachedFuturePrice = -1;
|
double CachedFuturePrice = -1;
|
||||||
string LoadedCSVPath = "";
|
string LoadedCSVPath = "";
|
||||||
bool CSVLoadLogged = false;
|
bool CSVLoadLogged = false;
|
||||||
|
datetime LastCSVReloadTime = 0;
|
||||||
|
|
||||||
int OnInit() {
|
int OnInit() {
|
||||||
Trade.SetExpertMagicNumber(InpMagicNumber);
|
Trade.SetExpertMagicNumber(InpMagicNumber);
|
||||||
@@ -301,13 +303,22 @@ void OnTick() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void OnTimer() {
|
void OnTimer() {
|
||||||
if(InpEnableDashboard && TimeCurrent() - LastDashboardUpdate >= 1) {
|
if(InpEnableDashboard && TimeCurrent() - LastDashboardUpdate >= 1) {
|
||||||
UpdateDashboard();
|
UpdateDashboard();
|
||||||
UpdateControlPanel();
|
UpdateControlPanel();
|
||||||
LastDashboardUpdate = TimeCurrent();
|
LastDashboardUpdate = TimeCurrent();
|
||||||
}
|
}
|
||||||
|
|
||||||
CheckDailyReset();
|
CheckDailyReset();
|
||||||
|
|
||||||
|
if(InpOISource == OI_SOURCE_CSV_FILE && InpCSVReloadInterval > 0) {
|
||||||
|
if(TimeCurrent() - LastCSVReloadTime >= InpCSVReloadInterval * 60) {
|
||||||
|
Print("CSV Reload: Scheduled reload triggered");
|
||||||
|
LastCSVReloadTime = TimeCurrent();
|
||||||
|
CachedFuturePrice = -1;
|
||||||
|
LoadOIFromCSV();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam) {
|
void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam) {
|
||||||
@@ -1007,111 +1018,71 @@ bool InitializeIndicators() {
|
|||||||
|
|
||||||
void LoadOIFromCSV()
|
void LoadOIFromCSV()
|
||||||
{
|
{
|
||||||
string paths[];
|
int filehandle = FileOpen(InpOICsvPath, FILE_READ | FILE_CSV | FILE_ANSI, ',');
|
||||||
int pathCount = 0;
|
|
||||||
|
if(filehandle == INVALID_HANDLE)
|
||||||
ArrayResize(paths, 5);
|
{
|
||||||
paths[pathCount++] = InpOICsvPath;
|
Print("CSV ERROR: Cannot open ", InpOICsvPath);
|
||||||
paths[pathCount++] = "oi_data.csv";
|
return;
|
||||||
paths[pathCount++] = "\\Files\\oi_data.csv";
|
}
|
||||||
paths[pathCount++] = "..\\oi_scraper\\oi_data.csv";
|
|
||||||
paths[pathCount++] = "../oi_scraper/oi_data.csv";
|
int callIndex = 0;
|
||||||
|
int putIndex = 0;
|
||||||
int filehandle = INVALID_HANDLE;
|
double futurePrice = 0.0;
|
||||||
string foundPath = "";
|
bool isFirstLine = true;
|
||||||
|
|
||||||
for(int i = 0; i < pathCount; i++) {
|
while(!FileIsEnding(filehandle) && (callIndex < 3 || putIndex < 3))
|
||||||
if(!CSVLoadLogged) {
|
{
|
||||||
Print("Trying CSV path: ", paths[i]);
|
string row = FileReadString(filehandle);
|
||||||
}
|
|
||||||
filehandle = FileOpen(paths[i], FILE_READ | FILE_CSV | FILE_ANSI, ',');
|
if(isFirstLine) {
|
||||||
if(filehandle != INVALID_HANDLE) {
|
isFirstLine = false;
|
||||||
foundPath = paths[i];
|
if(StringFind(row, "Type") >= 0 || StringFind(row, "Strike") >= 0 || StringFind(row, "OI") >= 0) {
|
||||||
if(!CSVLoadLogged) {
|
continue;
|
||||||
Print("Found CSV file at: ", foundPath);
|
}
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
}
|
string data[];
|
||||||
}
|
int count = StringSplit(row, ',', data);
|
||||||
|
|
||||||
if(filehandle == INVALID_HANDLE) {
|
if(count >= 3)
|
||||||
if(!CSVLoadLogged) {
|
{
|
||||||
Print("CSV ERROR: File not found. Searched paths:");
|
string type = data[0];
|
||||||
for(int i = 0; i < pathCount; i++) {
|
double strike = StringToDouble(data[1]);
|
||||||
Print(" - ", paths[i]);
|
int oi = (int)StringToInteger(data[2]);
|
||||||
}
|
|
||||||
CSVLoadLogged = true;
|
if(StringFind(type, "Future") >= 0)
|
||||||
}
|
{
|
||||||
return;
|
futurePrice = strike;
|
||||||
}
|
}
|
||||||
|
else if(type == "CALL" && callIndex < 3)
|
||||||
int callIndex = 0;
|
{
|
||||||
int putIndex = 0;
|
CallLevels[callIndex] = strike;
|
||||||
double futurePrice = 0.0;
|
CallOI[callIndex] = oi;
|
||||||
|
callIndex++;
|
||||||
while(!FileIsEnding(filehandle) && (callIndex < 3 || putIndex < 3))
|
}
|
||||||
{
|
else if(type == "PUT" && putIndex < 3)
|
||||||
string row = FileReadString(filehandle);
|
{
|
||||||
string data[];
|
PutLevels[putIndex] = strike;
|
||||||
int count = StringSplit(row, ',', data);
|
PutOI[putIndex] = oi;
|
||||||
|
putIndex++;
|
||||||
if(count >= 3)
|
}
|
||||||
{
|
}
|
||||||
string type = data[0];
|
}
|
||||||
double strike = StringToDouble(data[1]);
|
|
||||||
int oi = (int)StringToInteger(data[2]);
|
FileClose(filehandle);
|
||||||
|
|
||||||
if(StringFind(type, "Future") >= 0)
|
for(int i = callIndex; i < 3; i++) { CallLevels[i] = 0; CallOI[i] = 0; }
|
||||||
{
|
for(int i = putIndex; i < 3; i++) { PutLevels[i] = 0; PutOI[i] = 0; }
|
||||||
futurePrice = strike;
|
|
||||||
if(!CSVLoadLogged) {
|
if(futurePrice > 0) {
|
||||||
Print("DEBUG: Parsed Future price: ", futurePrice);
|
CachedFuturePrice = futurePrice;
|
||||||
}
|
DynamicFuturePrice = futurePrice;
|
||||||
}
|
FuturePrice = futurePrice;
|
||||||
else if(type == "CALL" && callIndex < 3)
|
Print("CSV SUCCESS: FuturePrice=", futurePrice);
|
||||||
{
|
}
|
||||||
CallLevels[callIndex] = strike;
|
|
||||||
CallOI[callIndex] = oi;
|
InitializeKeyLevels();
|
||||||
callIndex++;
|
|
||||||
}
|
|
||||||
else if(type == "PUT" && putIndex < 3)
|
|
||||||
{
|
|
||||||
PutLevels[putIndex] = strike;
|
|
||||||
PutOI[putIndex] = oi;
|
|
||||||
putIndex++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
FileClose(filehandle);
|
|
||||||
|
|
||||||
for(int i = callIndex; i < 3; i++)
|
|
||||||
{
|
|
||||||
CallLevels[i] = 0;
|
|
||||||
CallOI[i] = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
for(int i = putIndex; i < 3; i++)
|
|
||||||
{
|
|
||||||
PutLevels[i] = 0;
|
|
||||||
PutOI[i] = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(futurePrice > 0) {
|
|
||||||
CachedFuturePrice = futurePrice;
|
|
||||||
DynamicFuturePrice = futurePrice;
|
|
||||||
LoadedCSVPath = foundPath;
|
|
||||||
CSVLoadLogged = true;
|
|
||||||
Print("CSV SUCCESS: FuturePrice=", futurePrice, ", CALL=[", CallLevels[0], ",", CallLevels[1], ",", CallLevels[2], "], PUT=[", PutLevels[0], ",", PutLevels[1], ",", PutLevels[2], "] loaded from ", foundPath);
|
|
||||||
} else {
|
|
||||||
if(!CSVLoadLogged) {
|
|
||||||
Print("CSV ERROR: No valid price found in ", foundPath);
|
|
||||||
CSVLoadLogged = true;
|
|
||||||
}
|
|
||||||
CachedFuturePrice = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
InitializeKeyLevels();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CheckExistingPositions() {
|
void CheckExistingPositions() {
|
||||||
@@ -1355,34 +1326,6 @@ void UpdateInputValues() {
|
|||||||
DynamicFuturePrice = StringToDouble(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) {
|
|
||||||
CachedFuturePrice = -1;
|
|
||||||
LoadOIFromCSV();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(ObjectGetString(chart_id, "CP_CallStrike1", OBJPROP_TEXT, 0, value)) {
|
if(ObjectGetString(chart_id, "CP_CallStrike1", OBJPROP_TEXT, 0, value)) {
|
||||||
DynamicCallStrike1 = StringToDouble(value);
|
DynamicCallStrike1 = StringToDouble(value);
|
||||||
}
|
}
|
||||||
@@ -1403,9 +1346,10 @@ void UpdateInputValues() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
InitializeOILevels();
|
InitializeOILevels();
|
||||||
InitializeKeyLevels();
|
InitializeKeyLevels();
|
||||||
|
|
||||||
if(InpOISource == OI_SOURCE_CSV_FILE) {
|
if(InpOISource == OI_SOURCE_CSV_FILE) {
|
||||||
LoadOIFromCSV();
|
CachedFuturePrice = -1;
|
||||||
}
|
LoadOIFromCSV();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user