Market Data¶
📊 async bars(symbol, timeframe, *, count=None, since=None, until=None)¶
What it does: Fetches historical OHLC bars for the given symbol and timeframe.
Used in:
- Technical analysis, backtesting, visualization.
- Indicator calculations and statistical modeling.
- Pattern recognition and machine learning features.
- Strategy development and optimization.
Parameters:
symbol- Trading symbol (e.g., "EURUSD")timeframe- Bar period: "M1", "M5", "M15", "M30", "H1", "H4", "D1", "W1", "MN"count- (Optional) Number of most recent bars to fetchsince- (Optional) Start timestamp (epoch milliseconds)until- (Optional) End timestamp (epoch milliseconds)
Returns: List of dictionaries with keys: time, open, high, low, close, volume
Important notes:
- If backend doesn't support bars API, aggregates from ticks automatically
- Returns bars in chronological order (oldest first)
- Use
countfor simple "last N bars" queries - Use
since/untilfor date range queries
Related to: quote_history.md
Example 1: Get last 500 hourly bars
bars = await sugar.bars("EURUSD", timeframe="H1", count=500)
for b in bars:
print(b["time"], b["open"], b["high"], b["low"], b["close"])
Example 2: Calculate simple moving average
# Get last 20 bars
bars = await sugar.bars("EURUSD", timeframe="H1", count=20)
# Calculate SMA
closes = [b["close"] for b in bars]
sma_20 = sum(closes) / len(closes)
print(f"SMA(20): {sma_20}")
Example 3: Find support/resistance levels
# Get last 100 daily bars
bars = await sugar.bars("EURUSD", timeframe="D1", count=100)
# Find highest high and lowest low
highs = [b["high"] for b in bars]
lows = [b["low"] for b in bars]
resistance = max(highs)
support = min(lows)
print(f"Resistance: {resistance}, Support: {support}")
Example 4: Multi-timeframe analysis
# Get bars from different timeframes
h1_bars = await sugar.bars("EURUSD", timeframe="H1", count=100)
h4_bars = await sugar.bars("EURUSD", timeframe="H4", count=100)
d1_bars = await sugar.bars("EURUSD", timeframe="D1", count=100)
# Analyze trend across timeframes
h1_trend = "up" if h1_bars[-1]["close"] > h1_bars[-20]["close"] else "down"
h4_trend = "up" if h4_bars[-1]["close"] > h4_bars[-20]["close"] else "down"
d1_trend = "up" if d1_bars[-1]["close"] > d1_bars[-20]["close"] else "down"
if h1_trend == h4_trend == d1_trend:
print(f"Strong {h1_trend}trend across all timeframes")
🪶 async ticks(symbol, *, since=None, until=None, limit=None)¶
What it does: Returns historical tick data for the symbol starting from since (if provided).
Used in:
- High‑frequency analysis, custom bar building.
- Testing trading logic on raw tick data.
- Spread analysis and liquidity studies.
- Microsecond-level market microstructure analysis.
Parameters:
symbol- Trading symbolsince- (Optional) Start timestamp (epoch milliseconds)until- (Optional) End timestamp (epoch milliseconds)limit- (Optional) Maximum number of ticks to return
Returns: List of dictionaries with keys: time, bid, ask
Important notes:
- Tick data can be very large - use
limitto control size - Returns ticks in chronological order
- Time is in epoch milliseconds
Related to: quote_history.md
Example 1: Get last 100 ticks
ticks = await sugar.ticks("EURUSD", limit=100)
for t in ticks:
print(t["time"], t["bid"], t["ask"])
Example 2: Analyze spread over time
# Get last 1000 ticks
ticks = await sugar.ticks("EURUSD", limit=1000)
# Calculate spread for each tick
spreads = [(t["ask"] - t["bid"]) * 10000 for t in ticks] # in pips
avg_spread = sum(spreads) / len(spreads)
max_spread = max(spreads)
min_spread = min(spreads)
print(f"Average spread: {avg_spread:.1f} pips")
print(f"Max spread: {max_spread:.1f} pips")
print(f"Min spread: {min_spread:.1f} pips")
Example 3: Build custom 1-second bars from ticks
import time
# Get ticks for last 5 minutes
since_time = int((time.time() - 300) * 1000) # 5 minutes ago
ticks = await sugar.ticks("EURUSD", since=since_time)
# Group ticks into 1-second bars
bars = {}
for t in ticks:
second = t["time"] // 1000 # Round to second
if second not in bars:
bars[second] = {"open": t["bid"], "high": t["bid"], "low": t["bid"], "close": t["bid"]}
else:
bars[second]["high"] = max(bars[second]["high"], t["bid"])
bars[second]["low"] = min(bars[second]["low"], t["bid"])
bars[second]["close"] = t["bid"]
print(f"Created {len(bars)} 1-second bars")
⏳ async wait_price(symbol, target, direction='>=', timeout_s=None)¶
What it does: Waits until price crosses a target level in the specified direction. Returns the actual trigger price if satisfied within timeout, otherwise raises TimeoutError.
Used in:
- Automation flows that must "wait for price" before placing/closing orders.
- Syncing with real market movement without busy polling.
- Implementing price alerts and notifications.
- Conditional order placement strategies.
Parameters:
symbol- Trading symboltarget- Target price level to wait fordirection- Comparison operator: ">=", "<=", ">", "<"timeout_s- (Optional) Timeout in seconds. If None, waits indefinitely.
Returns: Actual mid-price that triggered the condition (float)
Raises: TimeoutError if timeout is reached before condition is met
Important notes:
- Uses mid price: (bid + ask) / 2
- Polls every 0.25 seconds (non-blocking)
- Raises TimeoutError on timeout (not returns False)
Related to: on_symbol_tick.md
Example 1: Wait for breakout above resistance
# Wait until price breaks 1.1050 resistance
try:
trigger_price = await sugar.wait_price(
"EURUSD",
target=1.1050,
direction=">=",
timeout_s=300 # 5 minutes
)
print(f"Breakout! Price: {trigger_price}")
# Enter long on breakout
await sugar.buy_market("EURUSD", lots=0.1, sl_pips=20, tp_pips=60)
except TimeoutError:
print("Timeout - no breakout occurred")
Example 2: Wait for pullback to support
# Wait for price to pull back to 1.0950 support
try:
trigger_price = await sugar.wait_price(
"EURUSD",
target=1.0950,
direction="<=",
timeout_s=600 # 10 minutes
)
print(f"Support reached at {trigger_price}")
await sugar.buy_limit("EURUSD", lots=0.1, price=1.0950, sl_pips=25)
except TimeoutError:
print("Support not reached within 10 minutes")
Example 3: Price alert system
async def price_alert(symbol, level, direction, message):
"""Send alert when price reaches level"""
try:
trigger_price = await sugar.wait_price(
symbol,
target=level,
direction=direction,
timeout_s=None # Wait indefinitely
)
logger.info(f"ALERT: {message} - Price: {trigger_price}")
await send_notification(message)
except Exception as e:
logger.error(f"Alert error: {e}")
# Run multiple alerts concurrently
import asyncio
await asyncio.gather(
price_alert("EURUSD", 1.1000, ">=", "EURUSD broke 1.1000!"),
price_alert("GBPUSD", 1.2500, "<=", "GBPUSD dropped to 1.2500!"),
price_alert("USDJPY", 150.00, ">=", "USDJPY hit 150!"),
)
Example 4: Conditional order entry
# Wait for price to reach specific level before entering
entry_level = 1.1000
# Wait for level to be reached
trigger_price = await sugar.wait_price("EURUSD", target=entry_level, direction=">=")
# Verify we still want to enter (conditions haven't changed)
spread = await sugar.spread_pips("EURUSD")
if spread < 2.0:
await sugar.buy_market("EURUSD", lots=0.1, sl_pips=20)
else:
logger.warning("Spread too high - skipping entry")