674 lines
24 KiB
MQL5
674 lines
24 KiB
MQL5
//+------------------------------------------------------------------+
| |||
//| CNewsImpactAnalyzer.mqh - Dynamic News-Based Threshold Adjustment |
| |||
//| Analyzes news impact in real-time and adjusts trading thresholds |
| |||
//| dynamically based on market conditions and news sentiment |
| |||
//+------------------------------------------------------------------+
| |||
#ifndef CNEWSIMPACTANALYZER_MQH
| |||
#define CNEWSIMPACTANALYZER_MQH
| |||
| |||
#include "CEconomicCalendar.mqh"
| |||
#include "CErrorRecovery.mqh"
| |||
| |||
// News impact state
| |||
enum ENUM_NEWS_STATE
| |||
{
| |||
NEWS_STATE_QUIET = 0, // No significant news
| |||
NEWS_STATE_WARNING = 1, // News approaching
| |||
NEWS_STATE_ACTIVE = 2, // News happening now
| |||
NEWS_STATE_AFTERMATH = 3 // Post-news volatility
| |||
};
| |||
| |||
// Threshold adjustment direction
| |||
enum ENUM_THRESHOLD_ADJUSTMENT
| |||
{
| |||
THRESHOLD_NORMAL = 0, // No adjustment
| |||
THRESHOLD_CONSERVATIVE = 1, // Increase thresholds (harder to trade)
| |||
THRESHOLD_AGGRESSIVE = 2, // Decrease thresholds (easier to trade)
| |||
THRESHOLD_BLOCK = 3 // Block trading completely
| |||
};
| |||
| |||
//+------------------------------------------------------------------+
| |||
//| Threshold Adjustment Result |
| |||
//+------------------------------------------------------------------+
| |||
struct SThresholdAdjustment
| |||
{
| |||
ENUM_THRESHOLD_ADJUSTMENT direction;
| |||
double confidence_multiplier;
| |||
double risk_multiplier;
| |||
double position_size_multiplier;
| |||
int sl_pips_adjustment;
| |||
int tp_pips_adjustment;
| |||
string reason;
| |||
datetime effective_until;
| |||
bool should_trade;
| |||
| |||
SThresholdAdjustment()
| |||
{
| |||
direction = THRESHOLD_NORMAL;
| |||
confidence_multiplier = 1.0;
| |||
risk_multiplier = 1.0;
| |||
position_size_multiplier = 1.0;
| |||
sl_pips_adjustment = 0;
| |||
tp_pips_adjustment = 0;
| |||
reason = "";
| |||
effective_until = 0;
| |||
should_trade = true;
| |||
}
| |||
};
| |||
| |||
//+------------------------------------------------------------------+
| |||
//| Market Response Metrics |
| |||
//+------------------------------------------------------------------+
| |||
struct SMarketResponse
| |||
{
| |||
double price_change_pct;
| |||
double volatility_spike;
| |||
double spread_widening;
| |||
int volume_surge;
| |||
bool is_trending;
| |||
int trend_direction;
| |||
datetime measurement_time;
| |||
| |||
SMarketResponse()
| |||
{
| |||
price_change_pct = 0.0;
| |||
volatility_spike = 0.0;
| |||
spread_widening = 0.0;
| |||
volume_surge = 0;
| |||
is_trending = false;
| |||
trend_direction = 0;
| |||
measurement_time = 0;
| |||
}
| |||
};
| |||
| |||
//+------------------------------------------------------------------+
| |||
//| News Impact History Entry |
| |||
//+------------------------------------------------------------------+
| |||
struct SNewsImpactHistory
| |||
{
| |||
long event_id;
| |||
string event_name;
| |||
datetime event_time;
| |||
int importance;
| |||
double actual_value;
| |||
double forecast_value;
| |||
double surprise_magnitude;
| |||
SMarketResponse market_response;
| |||
bool profitable_to_trade;
| |||
double ml_confidence_score;
| |||
| |||
SNewsImpactHistory()
| |||
{
| |||
event_id = 0;
| |||
event_name = "";
| |||
event_time = 0;
| |||
importance = 0;
| |||
actual_value = 0.0;
| |||
forecast_value = 0.0;
| |||
surprise_magnitude = 0.0;
| |||
profitable_to_trade = false;
| |||
ml_confidence_score = 0.0;
| |||
}
| |||
};
| |||
| |||
//+------------------------------------------------------------------+
| |||
//| News Impact Analyzer |
| |||
//+------------------------------------------------------------------+
| |||
class CNewsImpactAnalyzer
| |||
{
| |||
private:
| |||
static CNewsImpactAnalyzer* s_instance;
| |||
| |||
// Components
| |||
CEconomicCalendar* m_calendar;
| |||
CErrorRecovery* m_error_recovery;
| |||
| |||
// State tracking
| |||
ENUM_NEWS_STATE m_current_state;
| |||
datetime m_state_since;
| |||
SThresholdAdjustment m_current_adjustment;
| |||
| |||
// History for ML
| |||
SNewsImpactHistory m_impact_history[];
| |||
int m_history_count;
| |||
int m_max_history;
| |||
| |||
// Real-time metrics
| |||
double m_baseline_volatility;
| |||
double m_baseline_spread;
| |||
datetime m_baseline_measured;
| |||
int m_baseline_lookback_bars;
| |||
| |||
// Configuration
| |||
bool m_use_ml_predictions;
| |||
bool m_export_for_training;
| |||
string m_export_filename;
| |||
int m_volatility_measurement_bars;
| |||
double m_spread_widening_threshold;
| |||
double m_volatility_spike_threshold;
| |||
| |||
// Telemetry
| |||
int m_analysis_count;
| |||
int m_trade_blocked_count;
| |||
int m_threshold_adjusted_count;
| |||
| |||
public:
| |||
CNewsImpactAnalyzer()
| |||
{
| |||
m_calendar = CEconomicCalendar::Instance();
| |||
m_error_recovery = CErrorRecovery::Instance();
| |||
| |||
m_current_state = NEWS_STATE_QUIET;
| |||
m_state_since = 0;
| |||
| |||
m_history_count = 0;
| |||
m_max_history = 200;
| |||
ArrayResize(m_impact_history, m_max_history);
| |||
| |||
m_baseline_volatility = 0.0;
| |||
m_baseline_spread = 0.0;
| |||
m_baseline_measured = 0;
| |||
m_baseline_lookback_bars = 20;
| |||
| |||
m_use_ml_predictions = true;
| |||
m_export_for_training = true;
| |||
m_export_filename = "DualEA\\news_impact_training.csv";
| |||
m_volatility_measurement_bars = 10;
| |||
m_spread_widening_threshold = 1.5; // 150% of normal
| |||
m_volatility_spike_threshold = 2.0; // 200% of normal
| |||
| |||
m_analysis_count = 0;
| |||
m_trade_blocked_count = 0;
| |||
m_threshold_adjusted_count = 0;
| |||
}
| |||
| |||
~CNewsImpactAnalyzer()
| |||
{
| |||
}
| |||
| |||
static CNewsImpactAnalyzer* Instance()
| |||
{
| |||
if(s_instance == NULL)
| |||
s_instance = new CNewsImpactAnalyzer();
| |||
return s_instance;
| |||
}
| |||
| |||
static void Destroy()
| |||
{
| |||
if(s_instance != NULL)
| |||
{
| |||
delete s_instance;
| |||
s_instance = NULL;
| |||
}
| |||
}
| |||
| |||
//+------------------------------------------------------------------+
| |||
//| Configuration |
| |||
//+------------------------------------------------------------------+
| |||
void SetUseMLPredictions(bool use) { m_use_ml_predictions = use; }
| |||
void SetExportForTraining(bool export_data) { m_export_for_training = export_data; }
| |||
void SetBaselineLookback(int bars) { m_baseline_lookback_bars = bars; }
| |||
void SetSpreadThreshold(double threshold) { m_spread_widening_threshold = threshold; }
| |||
void SetVolatilityThreshold(double threshold) { m_volatility_spike_threshold = threshold; }
| |||
| |||
//+------------------------------------------------------------------+
| |||
//| Main analysis entry point |
| |||
//+------------------------------------------------------------------+
| |||
SThresholdAdjustment AnalyzeNewsImpact(const string symbol, int buffer_minutes_before = 30, int buffer_minutes_after = 60)
| |||
{
| |||
m_analysis_count++;
| |||
| |||
SThresholdAdjustment adjustment;
| |||
| |||
// Get news impact from calendar
| |||
SNewsImpact news_impact = m_calendar.CheckNewsImpact(symbol, buffer_minutes_before, buffer_minutes_after);
| |||
| |||
// Update baseline if needed
| |||
UpdateBaselineMetrics(symbol);
| |||
| |||
// Measure current market response
| |||
SMarketResponse response = MeasureMarketResponse(symbol);
| |||
| |||
// Determine news state
| |||
ENUM_NEWS_STATE new_state = DetermineNewsState(news_impact, response);
| |||
| |||
// Handle state transition
| |||
if(new_state != m_current_state)
| |||
{
| |||
Log("News state changed from " + StateToString(m_current_state) + " to " + StateToString(new_state));
| |||
m_current_state = new_state;
| |||
m_state_since = TimeCurrent();
| |||
}
| |||
| |||
// Calculate threshold adjustment
| |||
adjustment = CalculateThresholdAdjustment(new_state, news_impact, response);
| |||
m_current_adjustment = adjustment;
| |||
| |||
// Update statistics
| |||
if(!adjustment.should_trade)
| |||
m_trade_blocked_count++;
| |||
if(adjustment.direction != THRESHOLD_NORMAL)
| |||
m_threshold_adjusted_count++;
| |||
| |||
// Record for ML training
| |||
if(m_export_for_training && news_impact.is_news_time)
| |||
{
| |||
RecordForTraining(symbol, news_impact, response, adjustment);
| |||
}
| |||
| |||
return adjustment;
| |||
}
| |||
| |||
//+------------------------------------------------------------------+
| |||
//| Update baseline volatility and spread |
| |||
//+------------------------------------------------------------------+
| |||
void UpdateBaselineMetrics(const string symbol)
| |||
{
| |||
datetime now = TimeCurrent();
| |||
| |||
// Update every 5 minutes
| |||
if((now - m_baseline_measured) < 300)
| |||
return;
| |||
| |||
// Calculate baseline volatility (ATR)
| |||
int atr_handle = iATR(symbol, PERIOD_CURRENT, m_baseline_lookback_bars);
| |||
if(atr_handle != INVALID_HANDLE)
| |||
{
| |||
double atr[];
| |||
if(CopyBuffer(atr_handle, 0, 0, 1, atr) == 1)
| |||
{
| |||
m_baseline_volatility = atr[0];
| |||
}
| |||
IndicatorRelease(atr_handle);
| |||
}
| |||
| |||
// Get baseline spread
| |||
m_baseline_spread = SymbolInfoInteger(symbol, SYMBOL_SPREAD) * SymbolInfoDouble(symbol, SYMBOL_POINT);
| |||
| |||
m_baseline_measured = now;
| |||
}
| |||
| |||
//+------------------------------------------------------------------+
| |||
//| Measure current market response to news |
| |||
//+------------------------------------------------------------------+
| |||
SMarketResponse MeasureMarketResponse(const string symbol)
| |||
{
| |||
SMarketResponse response;
| |||
response.measurement_time = TimeCurrent();
| |||
| |||
// Price change over last N bars
| |||
MqlRates rates[];
| |||
if(CopyRates(symbol, PERIOD_CURRENT, 0, m_volatility_measurement_bars, rates) == m_volatility_measurement_bars)
| |||
{
| |||
double price_start = rates[0].close;
| |||
double price_end = rates[m_volatility_measurement_bars - 1].close;
| |||
response.price_change_pct = (price_end - price_start) / price_start * 100.0;
| |||
| |||
// Calculate volatility spike
| |||
double current_atr = 0.0;
| |||
for(int i = 1; i < m_volatility_measurement_bars; i++)
| |||
{
| |||
current_atr += MathMax(rates[i].high - rates[i].low,
| |||
MathMax(MathAbs(rates[i].high - rates[i-1].close),
| |||
MathAbs(rates[i].low - rates[i-1].close)));
| |||
}
| |||
current_atr /= m_volatility_measurement_bars;
| |||
| |||
if(m_baseline_volatility > 0)
| |||
{
| |||
response.volatility_spike = current_atr / m_baseline_volatility;
| |||
}
| |||
| |||
// Determine if trending
| |||
double highest_high = rates[0].high;
| |||
double lowest_low = rates[0].low;
| |||
for(int i = 1; i < m_volatility_measurement_bars; i++)
| |||
{
| |||
highest_high = MathMax(highest_high, rates[i].high);
| |||
lowest_low = MathMin(lowest_low, rates[i].low);
| |||
}
| |||
| |||
double range = highest_high - lowest_low;
| |||
if(range > 0)
| |||
{
| |||
response.is_trending = MathAbs(response.price_change_pct) > (range / price_start * 100.0 * 0.6);
| |||
response.trend_direction = (response.price_change_pct > 0) ? 1 : -1;
| |||
}
| |||
}
| |||
| |||
// Current spread vs baseline
| |||
double current_spread = SymbolInfoInteger(symbol, SYMBOL_SPREAD) * SymbolInfoDouble(symbol, SYMBOL_POINT);
| |||
if(m_baseline_spread > 0)
| |||
{
| |||
response.spread_widening = current_spread / m_baseline_spread;
| |||
}
| |||
| |||
// Volume surge (if available)
| |||
long volume[];
| |||
if(CopyTickVolume(symbol, PERIOD_CURRENT, 0, m_volatility_measurement_bars, volume) == m_volatility_measurement_bars)
| |||
{
| |||
long avg_volume = 0;
| |||
for(int i = 0; i < m_volatility_measurement_bars; i++)
| |||
{
| |||
avg_volume += volume[i];
| |||
}
| |||
avg_volume /= m_volatility_measurement_bars;
| |||
| |||
if(avg_volume > 0)
| |||
{
| |||
response.volume_surge = (int)((volume[m_volatility_measurement_bars - 1] * 100) / avg_volume);
| |||
}
| |||
}
| |||
| |||
return response;
| |||
}
| |||
| |||
//+------------------------------------------------------------------+
| |||
//| Determine current news state |
| |||
//+------------------------------------------------------------------+
| |||
ENUM_NEWS_STATE DetermineNewsState(const SNewsImpact &news, const SMarketResponse &response)
| |||
{
| |||
// Check for active news
| |||
if(news.is_news_time)
| |||
{
| |||
return NEWS_STATE_ACTIVE;
| |||
}
| |||
| |||
// Check for aftermath (high volatility after recent news)
| |||
if(response.volatility_spike > m_volatility_spike_threshold &&
| |||
(TimeCurrent() - m_state_since) < 1800) // Within 30 min of state change
| |||
{
| |||
return NEWS_STATE_AFTERMATH;
| |||
}
| |||
| |||
// Check for warning (news approaching within 15 minutes)
| |||
if(news.next_event_time > 0)
| |||
{
| |||
int seconds_to_event = (int)(news.next_event_time - TimeCurrent());
| |||
if(seconds_to_event > 0 && seconds_to_event <= 900) // 15 minutes
| |||
{
| |||
return NEWS_STATE_WARNING;
| |||
}
| |||
}
| |||
| |||
return NEWS_STATE_QUIET;
| |||
}
| |||
| |||
//+------------------------------------------------------------------+
| |||
//| Calculate threshold adjustment based on state |
| |||
//+------------------------------------------------------------------+
| |||
SThresholdAdjustment CalculateThresholdAdjustment(ENUM_NEWS_STATE state,
| |||
const SNewsImpact &news,
| |||
const SMarketResponse &response)
| |||
{
| |||
SThresholdAdjustment adj;
| |||
| |||
switch(state)
| |||
{
| |||
case NEWS_STATE_QUIET:
| |||
// Normal trading conditions
| |||
adj.direction = THRESHOLD_NORMAL;
| |||
adj.confidence_multiplier = 1.0;
| |||
adj.risk_multiplier = 1.0;
| |||
adj.position_size_multiplier = 1.0;
| |||
adj.should_trade = true;
| |||
adj.reason = "Normal market conditions";
| |||
break;
| |||
| |||
case NEWS_STATE_WARNING:
| |||
// News approaching - be more conservative
| |||
adj.direction = THRESHOLD_CONSERVATIVE;
| |||
adj.confidence_multiplier = 1.2; // 20% harder to meet confidence
| |||
adj.risk_multiplier = 0.8; // 20% less risk
| |||
adj.position_size_multiplier = 0.7; // 30% smaller positions
| |||
adj.sl_pips_adjustment = 5; // Wider SL
| |||
adj.tp_pips_adjustment = 3; // Wider TP
| |||
adj.should_trade = true;
| |||
adj.reason = "News approaching: " + news.next_event_name;
| |||
adj.effective_until = news.next_event_time + 3600; // 1 hour after event
| |||
break;
| |||
| |||
case NEWS_STATE_ACTIVE:
| |||
// News happening now - most conservative or block
| |||
if(news.current_importance >= EVENT_IMPORTANCE_HIGH)
| |||
{
| |||
adj.direction = THRESHOLD_BLOCK;
| |||
adj.should_trade = false;
| |||
adj.reason = "HIGH IMPACT NEWS ACTIVE: " + news.reason;
| |||
}
| |||
else
| |||
{
| |||
adj.direction = THRESHOLD_CONSERVATIVE;
| |||
adj.confidence_multiplier = 1.5; // 50% harder
| |||
adj.risk_multiplier = 0.5; // 50% less risk
| |||
adj.position_size_multiplier = 0.5; // 50% smaller
| |||
adj.sl_pips_adjustment = 10; // Much wider SL
| |||
adj.tp_pips_adjustment = 5;
| |||
adj.should_trade = true;
| |||
adj.reason = "News active: " + news.reason;
| |||
}
| |||
adj.effective_until = TimeCurrent() + 1800; // 30 minutes
| |||
break;
| |||
| |||
case NEWS_STATE_AFTERMATH:
| |||
// Post-news volatility - conservative
| |||
adj.direction = THRESHOLD_CONSERVATIVE;
| |||
adj.confidence_multiplier = 1.3;
| |||
adj.risk_multiplier = 0.7;
| |||
adj.position_size_multiplier = 0.6;
| |||
adj.should_trade = true;
| |||
adj.reason = "Post-news volatility detected";
| |||
adj.effective_until = TimeCurrent() + 900; // 15 minutes
| |||
break;
| |||
}
| |||
| |||
// Additional adjustments based on market response
| |||
if(response.volatility_spike > m_volatility_spike_threshold)
| |||
{
| |||
adj.confidence_multiplier *= 1.2;
| |||
adj.reason += " | High volatility detected";
| |||
}
| |||
| |||
if(response.spread_widening > m_spread_widening_threshold)
| |||
{
| |||
adj.confidence_multiplier *= 1.1;
| |||
adj.position_size_multiplier *= 0.8;
| |||
adj.reason += " | Spread widening";
| |||
}
| |||
| |||
return adj;
| |||
}
| |||
| |||
//+------------------------------------------------------------------+
| |||
//| Record data for ML training |
| |||
//+------------------------------------------------------------------+
| |||
void RecordForTraining(const string symbol,
| |||
const SNewsImpact &news,
| |||
const SMarketResponse &response,
| |||
const SThresholdAdjustment &adjustment)
| |||
{
| |||
// Build CSV line
| |||
string line = StringFormat("%s,%s,%.4f,%.4f,%.4f,%d,%.2f,%.2f,%d,%.2f,%d,%.2f,%s\n",
| |||
TimeToString(TimeCurrent(), TIME_DATE|TIME_SECONDS),
| |||
symbol,
| |||
news.volatility_prediction,
| |||
response.volatility_spike,
| |||
response.spread_widening,
| |||
response.volume_surge,
| |||
response.price_change_pct,
| |||
(double)response.is_trending,
| |||
adjustment.direction,
| |||
adjustment.confidence_multiplier,
| |||
(adjustment.should_trade ? 1 : 0),
| |||
CalculateProfitabilityScore(news, response),
| |||
news.reason
| |||
);
| |||
| |||
// Append to training file
| |||
int handle = FileOpen(m_export_filename,
| |||
FILE_WRITE|FILE_READ|FILE_CSV|FILE_COMMON,
| |||
',');
| |||
| |||
if(handle != INVALID_HANDLE)
| |||
{
| |||
FileSeek(handle, 0, SEEK_END);
| |||
| |||
// Write header if new file
| |||
if(FileSize(handle) == 0)
| |||
{
| |||
FileWriteString(handle,
| |||
"timestamp,symbol,volatility_prediction,volatility_spike,spread_widening," +
| |||
"volume_surge,price_change_pct,is_trending,threshold_direction," +
| |||
"confidence_multiplier,should_trade,profitability_score,news_reason\n");
| |||
}
| |||
| |||
FileWriteString(handle, line);
| |||
FileClose(handle);
| |||
}
| |||
}
| |||
| |||
//+------------------------------------------------------------------+
| |||
//| Calculate profitability score for ML (0-1) |
| |||
//+------------------------------------------------------------------+
| |||
double CalculateProfitabilityScore(const SNewsImpact &news, const SMarketResponse &response)
| |||
{
| |||
// This is a heuristic - in production, this would be calculated from actual trade results
| |||
double score = 0.5; // Neutral
| |||
| |||
// Reduce score for high volatility
| |||
if(response.volatility_spike > 2.0)
| |||
score -= 0.2;
| |||
| |||
// Reduce score for wide spreads
| |||
if(response.spread_widening > 1.5)
| |||
score -= 0.15;
| |||
| |||
// Increase score if trending clearly
| |||
if(response.is_trending && MathAbs(response.price_change_pct) > 0.1)
| |||
score += 0.15;
| |||
| |||
// Clamp
| |||
if(score < 0) score = 0;
| |||
if(score > 1) score = 1;
| |||
| |||
return score;
| |||
}
| |||
| |||
//+------------------------------------------------------------------+
| |||
//| Get current adjustment (cached) |
| |||
//+------------------------------------------------------------------+
| |||
SThresholdAdjustment GetCurrentAdjustment()
| |||
{
| |||
// Check if expired
| |||
if(m_current_adjustment.effective_until > 0 &&
| |||
TimeCurrent() > m_current_adjustment.effective_until)
| |||
{
| |||
// Reset to normal
| |||
m_current_adjustment = SThresholdAdjustment();
| |||
m_current_state = NEWS_STATE_QUIET;
| |||
}
| |||
| |||
return m_current_adjustment;
| |||
}
| |||
| |||
//+------------------------------------------------------------------+
| |||
//| Apply adjustment to a confidence value |
| |||
//+------------------------------------------------------------------+
| |||
double ApplyToConfidence(double base_confidence)
| |||
{
| |||
SThresholdAdjustment adj = GetCurrentAdjustment();
| |||
return base_confidence / adj.confidence_multiplier;
| |||
}
| |||
| |||
//+------------------------------------------------------------------+
| |||
//| Apply adjustment to position size |
| |||
//+------------------------------------------------------------------+
| |||
double ApplyToPositionSize(double base_lots)
| |||
{
| |||
SThresholdAdjustment adj = GetCurrentAdjustment();
| |||
return base_lots * adj.position_size_multiplier;
| |||
}
| |||
| |||
//+------------------------------------------------------------------+
| |||
//| Check if trading should proceed |
| |||
//+------------------------------------------------------------------+
| |||
bool ShouldTrade()
| |||
{
| |||
SThresholdAdjustment adj = GetCurrentAdjustment();
| |||
return adj.should_trade;
| |||
}
| |||
| |||
//+------------------------------------------------------------------+
| |||
//| Statistics and reporting |
| |||
//+------------------------------------------------------------------+
| |||
string GetStatistics()
| |||
{
| |||
string stats = StringFormat(
| |||
"=== News Impact Analyzer Statistics ===\n" +
| |||
"Analyses performed: %d\n" +
| |||
"Trades blocked: %d (%.1f%%)\n" +
| |||
"Thresholds adjusted: %d (%.1f%%)\n" +
| |||
"Current state: %s\n" +
| |||
"Training records: %d\n" +
| |||
"Baseline volatility: %.5f\n" +
| |||
"Baseline spread: %.5f",
| |||
m_analysis_count,
| |||
m_trade_blocked_count,
| |||
(m_analysis_count > 0 ? 100.0 * m_trade_blocked_count / m_analysis_count : 0),
| |||
m_threshold_adjusted_count,
| |||
(m_analysis_count > 0 ? 100.0 * m_threshold_adjusted_count / m_analysis_count : 0),
| |||
StateToString(m_current_state),
| |||
m_history_count,
| |||
m_baseline_volatility,
| |||
m_baseline_spread
| |||
);
| |||
| |||
return stats;
| |||
}
| |||
| |||
//+------------------------------------------------------------------+
| |||
//| Utility functions |
| |||
//+------------------------------------------------------------------+
| |||
string StateToString(ENUM_NEWS_STATE state)
| |||
{
| |||
switch(state)
| |||
{
| |||
case NEWS_STATE_QUIET: return "QUIET";
| |||
case NEWS_STATE_WARNING: return "WARNING";
| |||
case NEWS_STATE_ACTIVE: return "ACTIVE";
| |||
case NEWS_STATE_AFTERMATH: return "AFTERMATH";
| |||
default: return "UNKNOWN";
| |||
}
| |||
}
| |||
| |||
void Log(const string message)
| |||
{
| |||
Print("[NewsImpactAnalyzer] " + message);
| |||
}
| |||
| |||
// Getters
| |||
ENUM_NEWS_STATE GetCurrentState() const { return m_current_state; }
| |||
bool IsActive() const { return m_current_state != NEWS_STATE_QUIET; }
| |||
string GetCurrentReason() const { return m_current_adjustment.reason; }
| |||
};
| |||
| |||
// Static instance initialization
| |||
CNewsImpactAnalyzer* CNewsImpactAnalyzer::s_instance = NULL;
| |||
| |||
// Convenience macros
| |||
#define ANALYZE_NEWS(symbol) \
| |||
CNewsImpactAnalyzer::Instance().AnalyzeNewsImpact(symbol)
| |||
| |||
#define GET_NEWS_ADJUSTMENT() \
| |||
CNewsImpactAnalyzer::Instance().GetCurrentAdjustment()
| |||
| |||
#define SHOULD_TRADE_NEWS() \
| |||
CNewsImpactAnalyzer::Instance().ShouldTrade()
| |||
| |||
#define APPLY_NEWS_TO_CONFIDENCE(base_conf) \
| |||
CNewsImpactAnalyzer::Instance().ApplyToConfidence(base_conf)
| |||
| |||
#define APPLY_NEWS_TO_SIZE(base_lots) \
| |||
CNewsImpactAnalyzer::Instance().ApplyToPositionSize(base_lots)
| |||
| |||
#endif // CNEWSIMPACTANALYZER_MQH
|