Core & Defaults¶
🔌 async ensure_connected()¶
What it does: Ensures that the connection to the terminal is alive; automatically reconnects if lost.
Used in:
- Before any market operations (quotes, bars, orders).
- In long-running loops/workers to avoid silent disconnections.
- At the start of critical trading operations to guarantee connectivity.
- In scheduled tasks and background workers that run periodically.
How it works:
- Checks if the current connection is active by attempting to get session headers
- If connection is alive, returns immediately
- If connection is lost, attempts to reconnect automatically
- Emits a
on_reconnecthook event when reconnection succeeds - Raises an error if reconnection fails
Example 1: Basic usage before trading
# Ensure connection before any market calls
await sugar.ensure_connected()
price = await api.quote("EURUSD")
Example 2: In a long-running trading loop
while True:
# Guarantee connectivity at each iteration
await sugar.ensure_connected()
# Fetch market data
quote = await sugar.last_quote("EURUSD")
# Execute trading logic
if quote["bid"] > target_price:
await sugar.buy_market(lots=0.1, sl_pips=20)
await asyncio.sleep(60) # Wait 1 minute
Example 3: Error handling with fallback
try:
await sugar.ensure_connected()
# Proceed with trading operations
await sugar.buy_market("EURUSD", 0.1)
except ConnectivityError as e:
logger.error(f"Failed to establish connection: {e}")
# Notify admin or retry later
await notify_admin("MT4 connection lost")
🔎 get_default(key, fallback=None)¶
What it does: Returns a stored default value by key (symbol, magic, deviation_pips, risk_percent, etc.).
Used in:
- When you need to read the current default for logic/logging.
- In wrappers where some parameters are auto-filled.
- For debugging and diagnostic purposes to verify current configuration.
- In multi-strategy applications to check active trading context.
Available keys:
symbol- Default trading symbol (e.g., "EURUSD")magic- Magic number for order identificationdeviation_pips- Maximum allowed slippage in pipsslippage_pips- Alternative name for deviationrisk_percent- Default risk percentage per trade
Example 1: Basic retrieval
magic = sugar.get_default("magic", fallback=1001)
print("Current magic:", magic)
Example 2: Logging current configuration
def log_trading_config():
"""Log current Sugar API defaults for debugging"""
config = {
"symbol": sugar.get_default("symbol", "NOT_SET"),
"magic": sugar.get_default("magic", "NOT_SET"),
"deviation_pips": sugar.get_default("deviation_pips", 5),
"risk_percent": sugar.get_default("risk_percent", 1.0),
}
logger.info(f"Trading config: {config}")
Example 3: Conditional logic based on defaults
# Adjust strategy based on configured risk
risk_pct = sugar.get_default("risk_percent", fallback=1.0)
if risk_pct > 2.0:
logger.warning("High risk mode activated!")
# Use tighter stops
stop_pips = 15
else:
# Standard risk - wider stops
stop_pips = 30
📡 async ping()¶
What it does: Lightweight connection health check. Returns True/False.
Used in:
- Monitoring, watchdog loops, readiness probes before executing critical actions.
- Together with
ensure_connected()to quickly verify connectivity between operations. - Health check endpoints in web APIs or monitoring systems.
- Pre-flight checks before executing expensive or critical operations.
How it works:
- Attempts to get session headers (quick operation)
- If successful, returns
Trueimmediately - If failed, attempts one reconnection attempt
- Returns
Trueif reconnection succeeds,Falseotherwise - Never raises exceptions - always returns boolean
Example 1: Simple health check
# Health check between tasks
if not await sugar.ping():
await sugar.ensure_connected()
Example 2: Monitoring loop with alerting
async def health_monitor():
"""Monitor MT4 connection health every 30 seconds"""
while True:
is_healthy = await sugar.ping()
if not is_healthy:
logger.error("MT4 connection unhealthy!")
await send_alert("MT4 connection down")
else:
logger.debug("MT4 connection OK")
await asyncio.sleep(30)
Example 3: Pre-flight check for critical operations
async def execute_large_order(symbol, lots):
"""Execute large order with pre-flight connectivity check"""
# Pre-flight check
if not await sugar.ping():
raise RuntimeError("Cannot execute: MT4 connection unavailable")
# Connection OK - proceed with order
logger.info(f"Executing large order: {symbol} {lots} lots")
return await sugar.buy_market(symbol, lots)
Example 4: Web API health endpoint
from fastapi import FastAPI
app = FastAPI()
@app.get("/health/mt4")
async def mt4_health():
"""Health check endpoint for MT4 connectivity"""
is_connected = await sugar.ping()
return {
"status": "healthy" if is_connected else "unhealthy",
"service": "MT4",
"connected": is_connected
}
🧬 set_defaults(symbol=None, magic=None, deviation_pips=None, slippage_pips=None, risk_percent=None)¶
What it does: Sets human-friendly defaults that will be automatically injected into sugar calls.
Used in:
- Once during app/script startup.
- When switching trading contexts (different symbol, different
magic, etc.). - When changing trading strategies or risk profiles.
- In multi-strategy environments to isolate different trading contexts.
Parameters:
symbol- Default trading symbol (e.g., "EURUSD", "GBPUSD")magic- Magic number for order identification (integer)deviation_pips- Maximum allowed price deviation/slippage in pipsslippage_pips- Alternative parameter name for deviationrisk_percent- Default risk percentage per trade (e.g., 1.0 = 1%)
Important notes:
- Only non-None values are applied - existing defaults remain unchanged
- All parameters are optional
- Defaults persist until explicitly changed again
- Context-specific overrides can be done with
with_defaults()
Example 1: App bootstrap configuration
# App bootstrap: configure sane defaults
sugar.set_defaults(
symbol="EURUSD",
magic=1001,
deviation_pips=5,
slippage_pips=3,
risk_percent=1.0,
)
Example 2: Switching trading contexts
# Trade EURUSD with conservative settings
sugar.set_defaults(
symbol="EURUSD",
magic=1001,
risk_percent=0.5
)
await sugar.buy_market(lots=0.1) # Uses EURUSD, magic=1001
# Switch to GBPUSD with aggressive settings
sugar.set_defaults(
symbol="GBPUSD",
magic=2002,
risk_percent=2.0
)
await sugar.buy_market(lots=0.1) # Uses GBPUSD, magic=2002
Example 3: Strategy-specific configuration
class ScalpingStrategy:
def __init__(self, sugar):
self.sugar = sugar
# Configure for scalping
self.sugar.set_defaults(
symbol="EURUSD",
magic=5001,
deviation_pips=2, # Tight slippage for scalping
risk_percent=0.5 # Conservative risk
)
class SwingStrategy:
def __init__(self, sugar):
self.sugar = sugar
# Configure for swing trading
self.sugar.set_defaults(
symbol="GBPUSD",
magic=5002,
deviation_pips=10, # Allow wider slippage
risk_percent=2.0 # Higher risk for swing trades
)
Example 4: Partial updates
# Initial setup
sugar.set_defaults(
symbol="EURUSD",
magic=1001,
risk_percent=1.0
)
# Later: only update risk, keep symbol and magic unchanged
sugar.set_defaults(risk_percent=2.0)
# symbol="EURUSD" and magic=1001 remain unchanged
with_defaults(**overrides)¶
What it does: Temporarily override defaults in a limited context (within a code block).
Used in:
- Local scenarios: "for this section, trade GBPUSD with another magic."
- Tests/strategies where it's convenient to change context locally.
- Temporary context switches without affecting global configuration.
- Multi-symbol trading within a single strategy.
Important notes:
- Changes only affect code within the
withblock - Original defaults are automatically restored when exiting the block
- Can override multiple parameters simultaneously
- Nested contexts are supported
Example 1: Temporary symbol switch
# Global defaults: EURUSD
sugar.set_defaults(symbol="EURUSD", magic=1001)
# Temporarily switch trading context
with sugar.with_defaults(symbol="GBPUSD", magic=2002):
# Inside this block calls will use these defaults
await sugar.buy_market(lots=0.1) # uses symbol=GBPUSD, magic=2002
# Outside — back to EURUSD with magic=1001
await sugar.buy_market(lots=0.1) # uses symbol=EURUSD, magic=1001
Example 2: Multi-symbol correlation trading
# Main strategy on EURUSD
sugar.set_defaults(symbol="EURUSD", magic=1001)
# Check correlation with GBPUSD
gbpusd_spread = None
with sugar.with_defaults(symbol="GBPUSD"):
gbpusd_spread = await sugar.spread_pips()
# Check correlation with USDJPY
usdjpy_spread = None
with sugar.with_defaults(symbol="USDJPY"):
usdjpy_spread = await sugar.spread_pips()
# Main symbol EURUSD still active
eurusd_spread = await sugar.spread_pips() # Uses EURUSD
# Trade based on correlation
if eurusd_spread < 2.0 and gbpusd_spread < 3.0:
await sugar.buy_market(lots=0.1) # EURUSD
Example 3: Risk-adjusted hedging
# Main position with standard risk
sugar.set_defaults(symbol="EURUSD", risk_percent=1.0)
ticket_main = await sugar.buy_market(lots=0.1)
# Hedge with lower risk
with sugar.with_defaults(symbol="EURUSD", risk_percent=0.5):
lots_hedge = await sugar.calc_lot_by_risk(stop_pips=20)
ticket_hedge = await sugar.sell_market(lots=lots_hedge)
# Back to standard risk for next trade
# risk_percent=1.0 restored automatically
Example 4: Nested contexts
sugar.set_defaults(symbol="EURUSD", magic=1001, risk_percent=1.0)
with sugar.with_defaults(symbol="GBPUSD"):
# GBPUSD, magic=1001, risk_percent=1.0
await sugar.buy_market(lots=0.1)
with sugar.with_defaults(risk_percent=2.0):
# GBPUSD, magic=1001, risk_percent=2.0 (nested)
lots = await sugar.calc_lot_by_risk(stop_pips=20)
await sugar.buy_market(lots=lots)
# Back to GBPUSD, magic=1001, risk_percent=1.0
# Back to EURUSD, magic=1001, risk_percent=1.0
Example 5: Testing with different configurations
async def test_strategy_with_different_risks():
"""Test how strategy performs with different risk levels"""
for risk_pct in [0.5, 1.0, 2.0, 3.0]:
with sugar.with_defaults(risk_percent=risk_pct):
lots = await sugar.calc_lot_by_risk(stop_pips=20)
logger.info(f"Risk {risk_pct}% -> Lot size: {lots}")
# Original risk_percent restored after loop