Market Depth Analysis Strategy#
Trading Risk Warning
IMPORTANT: All examples should be tested using demo accounts only!
- Trading involves substantial risk of loss
- These examples are for educational purposes only
- Always test with fake money before using real funds
Overview#
Market Depth Analysis (also known as DOM or Depth of Market analysis) examines the order book data to understand supply and demand dynamics that aren't visible on price charts alone. This approach allows traders to:
- See the actual buy and sell orders waiting to be executed at various price levels
- Identify potential support and resistance levels based on order concentration
- Gauge market sentiment through imbalances in buy and sell orders
- Anticipate potential price movements based on order flow patterns
Market depth data consists of:
Component | Description |
---|---|
Buy Orders (Bids) | Orders to buy at specific prices, appearing below current market price |
Sell Orders (Asks) | Orders to sell at specific prices, appearing above current market price |
Volume | The quantity associated with each order at a particular price level |
This analysis tool doesn't generate direct trading signals but provides valuable context for making informed trading decisions.
Analysis Logic#
Step | Description |
---|---|
1 | Connect to MetaTrader 5 and retrieve order book (market depth) data |
2 | Analyze buy/sell order distribution and calculate key metrics |
3 | Identify price levels with unusually high order concentration |
4 | Visualize the order book structure and highlight significant levels |
5 | Track changes in order book structure over time |
Analysis Flow#
flowchart TD
A[Start] --> B[Connect to MT5]
B --> C[Fetch Market Depth Data]
C --> D[Calculate Buy/Sell Metrics]
D --> E[Calculate Volume Distribution]
E --> F[Identify Significant<br/>Price Levels]
F --> G[Classify as Support<br/>or Resistance]
G --> H[Create Visualization]
H --> I[Log Analysis Results]
I --> J[Wait for Next Snapshot<br/>Interval]
J --> C
Code Implementation#
Let's break down the implementation step by step:
Step 1: Required Imports#
from __future__ import annotations
import logging
import time
import matplotlib.pyplot as plt
from mqpy.tick import MqlBookInfo, Tick
from mqpy.trade import Trade
# Configure logging
logging.basicConfig(level=logging.INFO, format="%(asctime)s - %(levelname)s - %(message)s")
logger = logging.getLogger(__name__)
We import the necessary modules:
- Core MQPy modules for accessing market data and trading functionality
- matplotlib
for visualizing the market depth data
- logging
for tracking the analysis process
- Type hints for better code readability
Step 2: Market Depth Analysis Function#
def analyze_market_depth(book_info: list[MqlBookInfo]) -> tuple[dict[str, float], dict[float, int]]:
"""Analyze market depth information to extract trading insights.
Args:
book_info: List of MqlBookInfo objects containing the market depth data
Returns:
Tuple containing market metrics and volume distribution by price
"""
if not book_info:
logger.warning("Empty market depth data received")
return {}, {}
# Initialize counters
buy_volume = 0
sell_volume = 0
buy_orders = 0
sell_orders = 0
# Dictionary to track volume at each price level
volume_by_price: dict[float, int] = {}
# Process each entry in the order book
for entry in book_info:
# Track volume by price
volume_by_price[entry.price] = volume_by_price.get(entry.price, 0) + entry.volume
if entry.type == 1: # Buy orders (bids)
buy_volume += entry.volume
buy_orders += 1
elif entry.type == 2: # Sell orders (asks)
sell_volume += entry.volume
sell_orders += 1
# Calculate market metrics
total_volume = buy_volume + sell_volume
buy_percentage = (buy_volume / total_volume) * 100 if total_volume > 0 else 0
sell_percentage = (sell_volume / total_volume) * 100 if total_volume > 0 else 0
# Calculate buy/sell ratio
buy_sell_ratio = buy_volume / sell_volume if sell_volume > 0 else float("inf")
# Package results
metrics = {
"buy_volume": buy_volume,
"sell_volume": sell_volume,
"buy_orders": buy_orders,
"sell_orders": sell_orders,
"buy_percentage": buy_percentage,
"sell_percentage": sell_percentage,
"buy_sell_ratio": buy_sell_ratio,
"total_orders": buy_orders + sell_orders,
"total_volume": total_volume,
}
return metrics, volume_by_price
This function analyzes the raw order book data: 1. It processes each entry in the market depth to track buy and sell volumes 2. It maintains a dictionary that maps price levels to their total volume 3. It calculates key metrics including buy/sell ratio and percentage distribution 4. It returns both the summary metrics and the volume distribution for further analysis
Step 3: Support/Resistance Detection Function#
def identify_support_resistance(
volume_by_price: dict[float, int], threshold_factor: float = 1.5
) -> list[dict[str, Any]]:
"""Identify potential support and resistance levels based on volume concentration.
Args:
volume_by_price: Dictionary mapping price levels to their volume
threshold_factor: Multiplier for the average volume to identify significant levels
Returns:
List of dictionaries containing identified support/resistance levels
"""
if not volume_by_price:
return []
# Calculate average volume
volumes = list(volume_by_price.values())
avg_volume = sum(volumes) / len(volumes)
threshold = avg_volume * threshold_factor
# Find price levels with volume above threshold
significant_levels = []
# Sort price levels for easier analysis
sorted_prices = sorted(volume_by_price.keys())
for price in sorted_prices:
volume = volume_by_price[price]
if volume > threshold:
# Determine if this is likely support or resistance
# This is a simplistic approach - in reality, you'd need more context
# We'll use a simple heuristic based on position in the order book
median_price = sorted_prices[len(sorted_prices) // 2]
level_type = "support" if price < median_price else "resistance"
significant_levels.append(
{
"price": price,
"volume": volume,
"type": level_type,
"strength": volume / avg_volume, # Relative strength factor
}
)
return significant_levels
This function identifies potential support and resistance levels: 1. It calculates the average volume across all price levels 2. It identifies price levels with volume significantly above average (using a threshold factor) 3. It classifies each level as support or resistance based on its position relative to the median price 4. It calculates a "strength" factor for each level based on how much its volume exceeds the average 5. It returns a list of identified levels with their characteristics
Step 4: Visualization Function#
def plot_market_depth(book_info: list[MqlBookInfo], metrics: dict[str, float], levels: list[dict[str, Any]]) -> None:
"""Visualize market depth data and identified support/resistance levels.
Args:
book_info: List of MqlBookInfo objects containing the market depth data
metrics: Dictionary of market metrics from analyze_market_depth
levels: List of identified support/resistance levels
"""
try:
# Extract data for plotting
buy_prices = []
buy_volumes = []
sell_prices = []
sell_volumes = []
for entry in book_info:
if entry.type == 1: # Buy orders
buy_prices.append(entry.price)
buy_volumes.append(entry.volume)
elif entry.type == 2: # Sell orders
sell_prices.append(entry.price)
sell_volumes.append(entry.volume)
# Create the plot
plt.figure(figsize=(12, 8))
# Plot buy orders (bids) in green
plt.barh(buy_prices, buy_volumes, color="green", alpha=0.6, label="Bids (Buy Orders)")
# Plot sell orders (asks) in red
plt.barh(sell_prices, sell_volumes, color="red", alpha=0.6, label="Asks (Sell Orders)")
# Highlight support/resistance levels
for level in levels:
plt.axhline(
y=level["price"],
color="purple",
linestyle="--",
alpha=0.7,
label=f"{level['type'].capitalize()} ({level['price']})",
)
# Add labels and title
plt.title(f"Market Depth Analysis\nBuy/Sell Ratio: {metrics['buy_sell_ratio']:.2f}", fontsize=14)
plt.xlabel("Volume", fontsize=12)
plt.ylabel("Price", fontsize=12)
plt.grid(True, alpha=0.3)
# Add buy/sell percentage annotation
annotation_text = (
f"Buy Volume: {metrics['buy_volume']} ({metrics['buy_percentage']:.1f}%)\n"
f"Sell Volume: {metrics['sell_volume']} ({metrics['sell_percentage']:.1f}%)\n"
f"Total Orders: {metrics['total_orders']}"
)
plt.annotate(
annotation_text,
xy=(0.02, 0.02),
xycoords="axes fraction",
bbox=dict(boxstyle="round,pad=0.5", fc="white", alpha=0.8),
)
# Clean up the legend (limit to unique entries)
handles, labels = plt.gca().get_legend_handles_labels()
by_label = dict(zip(labels, handles))
plt.legend(by_label.values(), by_label.keys(), loc="best")
# Save the plot
plt.tight_layout()
plt.savefig("market_depth_analysis.png")
logger.info("Market depth visualization saved as 'market_depth_analysis.png'")
plt.close()
except Exception:
logger.exception("Error creating market depth visualization")
This visualization function creates a horizontal bar chart of the order book: 1. It separates buy and sell orders for plotting 2. It creates a horizontal bar chart with buy orders in green and sell orders in red 3. It highlights identified support/resistance levels with horizontal lines 4. It adds annotations with key metrics like buy/sell ratio and percentages 5. It saves the visualization to a file for later analysis
Step 5: Initialize the Trade Object#
trade = Trade(
expert_name="Market Depth Analyzer",
version="1.0",
symbol="EURUSD",
magic_number=573,
lot=0.1,
stop_loss=30,
emergency_stop_loss=90,
take_profit=60,
emergency_take_profit=180,
start_time="9:15",
finishing_time="17:30",
ending_time="17:50",
fee=0.5,
)
We initialize the Trade object to: - Identify our analysis tool with a name and version - Specify the trading instrument (EURUSD) - Set a unique magic number - Configure risk management parameters (even though this is primarily an analysis tool, not a trading strategy) - Define session trading hours
Step 6: Main Analysis Loop#
# Previous tick time to track new ticks
prev_tick_time = 0
# Track depth changes
depth_snapshots: list[list[MqlBookInfo]] = []
snapshot_timestamps: list[int] = []
last_snapshot_time = 0
try:
# Main loop
while True:
# Prepare the symbol for trading
trade.prepare_symbol()
# Fetch current tick data
current_tick = Tick(trade.symbol)
# Only process if we have a new tick
if current_tick.time_msc != prev_tick_time:
try:
# Get market depth data
book_info = current_tick.get_book()
In the main loop: - We initialize variables to track tick times and store snapshots - We prepare the symbol and get the current tick data - We only process new ticks to avoid redundant calculations - We retrieve the current market depth (order book) data
Step 7: Snapshot Collection and Analysis#
# Check if we have valid market depth data
if book_info and len(book_info) > 0:
# Take snapshots at regular intervals (every 10 seconds)
current_time = int(time.time())
if current_time - last_snapshot_time >= 10:
# Store the snapshot
depth_snapshots.append(book_info)
snapshot_timestamps.append(current_time)
last_snapshot_time = current_time
# Keep only the last 10 snapshots
if len(depth_snapshots) > 10:
depth_snapshots.pop(0)
snapshot_timestamps.pop(0)
# Analyze the current market depth
metrics, volume_by_price = analyze_market_depth(book_info)
# Log key metrics
logger.info(
f"Market depth snapshot at {time.strftime('%H:%M:%S', time.localtime(current_time))}"
)
logger.info(f"Buy/Sell Ratio: {metrics['buy_sell_ratio']:.2f}")
logger.info(f"Buy Volume: {metrics['buy_volume']} ({metrics['buy_percentage']:.1f}%)")
logger.info(f"Sell Volume: {metrics['sell_volume']} ({metrics['sell_percentage']:.1f}%)")
We collect and analyze market depth snapshots: 1. We take snapshots at regular intervals (every 10 seconds) 2. We maintain a rolling history of the last 10 snapshots 3. We analyze each snapshot to calculate key metrics 4. We log the results for monitoring
Step 8: Support/Resistance Identification and Visualization#
# Identify potential support and resistance levels
levels = identify_support_resistance(volume_by_price)
if levels:
logger.info("Potential support/resistance levels:")
for level in levels:
logger.info(
f"{level['type'].capitalize()} at {level['price']} "
f"(strength: {level['strength']:.1f}x average)"
)
# Create a visualization every 30 seconds
if len(depth_snapshots) % 3 == 0:
plot_market_depth(book_info, metrics, levels)
For each analyzed snapshot: 1. We identify potential support and resistance levels 2. We log the identified levels with their characteristics 3. We create a visualization every 30 seconds (every 3rd snapshot)
Step 9: Error Handling and Shutdown#
except Exception:
logger.exception("Error processing market depth data")
# Update previous tick time
prev_tick_time = current_tick.time_msc
# Check if it's the end of the trading day
if trade.days_end():
logger.info("End of trading day reached.")
break
# Add a short delay to avoid excessive CPU usage
time.sleep(0.1)
except KeyboardInterrupt:
logger.info("Analysis interrupted by user")
except Exception:
logger.exception("Error in market depth analysis")
finally:
logger.info("Finishing market depth analysis")
# Create a final visualization if we have data
if depth_snapshots:
try:
# Analyze the most recent snapshot
metrics, volume_by_price = analyze_market_depth(depth_snapshots[-1])
levels = identify_support_resistance(volume_by_price)
plot_market_depth(depth_snapshots[-1], metrics, levels)
logger.info("Final market depth visualization saved")
except Exception:
logger.exception("Error creating final visualization")
We implement comprehensive error handling: 1. We catch and log exceptions during market depth processing 2. We check for the end of the trading day 3. We handle user interruptions 4. We create a final visualization before shutting down
Interpreting the Results#
The Market Depth analysis provides several key insights:
Metric | Interpretation |
---|---|
Buy/Sell Ratio > 1.0 | Indicates stronger buying pressure; potentially bullish |
Buy/Sell Ratio < 1.0 | Indicates stronger selling pressure; potentially bearish |
Strong Support Level | A price level with high buy order concentration; may prevent price from falling further |
Strong Resistance Level | A price level with high sell order concentration; may prevent price from rising further |
Level Strength | How significant a support/resistance level is compared to average (higher is stronger) |
Practical Applications#
Here are some ways to apply market depth analysis to your trading:
-
Confirmation Tool: Use identified support/resistance levels to confirm technical analysis from price charts.
-
Entry/Exit Timing: Watch how price interacts with levels of high order concentration for optimal trade timing.
-
Stop-Loss Placement: Set stops beyond significant support/resistance levels that have high order volume.
-
Market Sentiment: Track buy/sell ratio changes over time to gauge shifts in market sentiment.
-
Spotting Manipulation: Unusually large orders or sudden changes in the order book may indicate institutional activity.
Conclusion#
Market Depth Analysis provides a window into the supply and demand dynamics that drive price movement. By examining the actual order book data rather than just price action, traders can gain valuable insights into market structure and sentiment.
While not a standalone trading strategy, this analysis tool can significantly enhance trading decisions when combined with other technical and fundamental approaches. It's particularly valuable for short-term traders who need to understand immediate market dynamics and liquidity conditions.