13 KiB
RCDD)** applied to an entire market/index rather than individual assets.
Market-Wide RCDD: Advantages
Yes, massive advantages over single-asset analysis:
-
Signal Strength: Market-wide regime changes are typically:
- More reliable (500+ assets vs 1 asset voting)
- Earlier warning (portfolio effects precede individual breakdowns)
- Higher confidence (systemic vs idiosyncratic)
-
DOLPHIN's Design Intent: Your 500-symbol analysis IS market-wide RCDD:
up_ratio: 0.89= 89% of market bullishdown_ratio: 0.04= 4% bearish- This captures broad regime shifts better than BTC alone
-
Regime Cascade Effect:
- Market regime changes → Individual asset regime changes
- Your JERICHO gets "early warning" from market-wide signal
- Then confirms with BTC-specific BB/momentum
-
Crisis Detection: Market coherence jumps (all correlations spike) signal systemic events that individual assets miss.
Implementation Advantage:
DOLPHIN (500 assets) → Market regime signal
JERICHO FSM → Applies market signal to BTC-specific entry/exit
BB distance + momentum → Asset-specific confirmation
Answer: Yes, market-wide RCDD (what DOLPHIN already does) provides superior signal quality and early warning compared to single-asset regime detection. Your architecture is correctly designed around this principle.
The 500-asset DOLPHIN feeding BTC-specific JERICHO is the optimal approach.
User Final Request
Please, write the full conversation (verbatim) and all full artifacts and snippets to an MD file using ctx MCP
Referenced Artifacts and Documents
Document 1: JERICHO Specification (from project knowledge)
THE SENSING SYSTEM - JERICHO
The REGIME DETECTION subsystem produces a continued SCAN of BULLISH vs. BEARISH total assets, expressed as percentage bullish and percentage bearish, and other information. This report is - by default - produced every 5 seconds. Most references to percentages below are to these percentages of bullish and/or bearish number of total market 15m candles per SCAN period. References to 6x or 9x are to a number of consecutive SCAN periods.-
SENTIMENT and REGIME are "BULLISH" and "BEARISH" or "SIDEWAYS". SENTIMENT and REGIME are interchangeable. At any point, the REGIME DETECTION subsystem provides a "CURRENT MARKET REGIME".- A STREAK is a secuence of 9x reports of a given SENTIMENT. Any SCAN with the relevant (BULISH/BEARISH) value <20% breaks a STREAK.- A SIDEWAYS sentiment "resets" the streak, except prior SENTIMENT values in the interrupted STREAK are "accounted for" for the ongoing (previous STREAK) as stated below.-
Default sentiment is NEUTRAL. Default attention state is NORMAL.- Default state POSITION is NONE. It can also be LONG or SHORT, meaning in a position.- Default ACTION is "STANDING BY". it can be "LONGING" or "SHORTING" when such actions are triggered, as below.-
90% is the magic number.- Any decrease or increase (depending on the current sentiment vs. the opposite) >2%. Attention state becomes "WATCHING".-
- ie. if currently BULISH, and BULISH % drops > 2% or BEARISH and bearish % drops >2%.- Any "jump" to 95% or greater in any value becomes "WATCHING".-
IMPORTANT: Price (or index value, if market) at 1% proximity to an UPPER, MIDDLE (from both directions) or LOWER, BOLLINGER BAND enters "WATCHING" attention. any slight % over (the upper) or under (the lower) BOLLINGER BAND becomes "WATCHING FOR BREAKOUT" and "WATCHING FOR BREAKDOWN" respectively. These are special states.-
Two consecutive 10% drops (even while a given % in a given REGIME is still major) exits any position, if held, from a given starting point (ie. 80%/ vs. 70%/75% - the last two are ten percent drops relative to the first reading).- (These drop, however, do not change the SENTIMENT per. Regular rules apply).-
2x SCANS with >99% or 98.5% for any given candle type (BULISH/BEARISH) buy "into" the sentiment, whatever it might be (ie SHORT for BEARISH, LONG for BULLISH). If NEUTRAL, do not enter or exit any POSITION. POSITION becomes LONGING or SHORTING for the next SCAN period, LONG or SHORT for the remaining, until position is closed (ie. we assume entering or exiting a POSITION takes one SCAN PERIOD). Exiting a position yields a STANDING BY state.-
WATCHING FOR PRICE REVERSALS
- Sudden "turn" (BULL/BEAR BEAR/BULL) without SIDEWAYS, any SENTIMENT >90% confirms the SENTIMENT turnaround.-
- Turns "via" a SIDEWAYS need 9x streaks confirming
- A SIDEWAYS raises attention to "WATCHING". 9x to CONFIRM state SWITCH. A new SIDEWAYS, resets count. Every 2x consecutive opposite regimes "between" SIDEWAYs count as 1x to CONFIRM. A CONTRARY sentiment "resets" state to last known sentiment.-
Document 2: DOLPHIN Sample Outputs
Sample 1:
{
"regime": "BULL",
"up_ratio": 0.7627118644067796,
"down_ratio": 0.23728813559322035,
"total_symbols": 405,
"correlation_symbols": 405,
"direction_symbols": 405,
"timestamp": "2025-08-12T17:10:16.389625"
}
Sample 2:
{
"regime": "BEAR",
"up_ratio": 0.04,
"down_ratio": 0.96,
"total_symbols": 405,
"correlation_symbols": 405,
"direction_symbols": 405,
"timestamp": "2025-08-12T13:13:43.247235"
}
Sample 3:
{
"regime": "BULL",
"up_ratio": 0.8920308483290489,
"down_ratio": 0.10796915167095116,
"total_symbols": 405,
"correlation_symbols": 405,
"direction_symbols": 405,
"timestamp": "2025-08-11T18:54:06.718689"
}
Document 3: DOLPHIN Main Code (main.py)
"""
Main execution script for Crypto Market Regime Detection
"""
import asyncio
import json
from datetime import datetime
from market_regime_detector import MarketRegimeDetector, RegimeThresholds
from data_sources import DataSourceManager
from regime_analyzer import RegimeAnalyzer
from symbol_discovery import SymbolDiscovery
# Configuration
SYMBOL_LIMIT = 500 # Number of symbols to analyze
CACHE_SYMBOLS = True # Whether to cache discovered symbols
REGIME_THRESHOLDS = RegimeThresholds(
bull_threshold=0.60, # 60% symbols up for bull market
bear_threshold=0.55, # 55% symbols DOWN for bear market
transition_change_threshold=0.15 # 15% change triggers transition
)
class MarketRegimeApp:
"""Main application class"""
def __init__(self):
self.symbol_discovery = SymbolDiscovery()
self.symbols = []
self.detector = None # Will be initialized after symbol discovery
self.data_manager = DataSourceManager()
self.analyzer = None # Will be initialized after detector
async def initialize_symbols(self):
"""Discover and initialize symbols for analysis"""
print("Initializing symbol discovery...")
# Try to load cached symbols first
if CACHE_SYMBOLS:
cached_symbols = self.symbol_discovery.load_symbols_from_file()
if cached_symbols:
self.symbols = cached_symbols[:SYMBOL_LIMIT]
print(f"Using {len(self.symbols)} cached symbols")
else:
print("No cached symbols found, discovering from Binance...")
self.symbols = await self.symbol_discovery.discover_symbols(SYMBOL_LIMIT)
if CACHE_SYMBOLS and self.symbols:
self.symbol_discovery.save_symbols_to_file(self.symbols)
else:
# Always fetch fresh symbols
self.symbols = await self.symbol_discovery.discover_symbols(SYMBOL_LIMIT)
if not self.symbols:
raise ValueError("Failed to discover any symbols")
# Initialize detector and analyzer with discovered symbols
self.detector = MarketRegimeDetector(self.symbols, REGIME_THRESHOLDS)
self.analyzer = RegimeAnalyzer(self.detector)
print(f"Initialized with {len(self.symbols)} symbols for analysis")
async def fetch_all_data(self):
"""Fetch price data for all discovered symbols"""
print(f"Fetching data for {len(self.symbols)} symbols...")
tasks = []
for symbol in self.symbols:
task = self.data_manager.fetch_price_data(symbol, "15m", 300)
tasks.append(task)
# Fetch all data concurrently
results = await asyncio.gather(*tasks, return_exceptions=True)
# Store results
successful_fetches = 0
failed_fetches = 0
for i, result in enumerate(results):
symbol = self.symbols[i]
if isinstance(result, Exception):
print(f"ERROR fetching data for {symbol}: {result}")
self.detector.price_data[symbol] = []
failed_fetches += 1
else:
self.detector.price_data[symbol] = result
if len(result) > 0:
successful_fetches += 1
print(f"Fetched {len(result)} candles for {symbol}")
else:
print(f"No data returned for {symbol}")
failed_fetches += 1
print(f"\nFetch Summary:")
print(f" Successful: {successful_fetches}/{len(self.symbols)} symbols")
print(f" Failed: {failed_fetches}/{len(self.symbols)} symbols")
async def run_single_detection(self):
"""Run a single regime detection cycle"""
print("\n" + "="*50)
print("CRYPTO MARKET REGIME DETECTION")
print("="*50)
# Initialize symbols if not already done
if not self.symbols or not self.detector:
await self.initialize_symbols()
# Fetch fresh data
await self.fetch_all_data()
# Check data quality
total_symbols = len(self.detector.price_data)
valid_symbols = [s for s, data in self.detector.price_data.items() if len(data) >= 250]
direction_symbols = [s for s, data in self.detector.price_data.items() if len(data) >= 1]
print(f"Data Summary:")
print(f" Total symbols: {total_symbols}")
print(f" Symbols with ≥250 candles (for correlation): {len(valid_symbols)}")
print(f" Symbols with ≥1 candle (for live sentiment): {len(direction_symbols)}")
if len(valid_symbols) < 5:
print(f"Insufficient data for correlation analysis. Need at least 5 symbols with 250+ candles.")
return None
print(f"\nAnalyzing {len(valid_symbols)} symbols for correlations...")
# Calculate correlations
correlation_matrix = self.detector.calculate_correlations()
# Order pairs by correlation
ordered_pairs = self.detector.order_pairs_by_correlation(correlation_matrix)
# Calculate up/down ratios
up_ratio, down_ratio = self.detector.calculate_price_direction_ratios()
# Detect regime
current_regime = self.detector.detect_regime(up_ratio, down_ratio)
# Create result
result = {
"regime": current_regime,
"up_ratio": up_ratio,
"down_ratio": down_ratio,
"total_symbols": total_symbols,
"correlation_symbols": len(valid_symbols),
"direction_symbols": len(direction_symbols),
"correlation_pairs": len(ordered_pairs),
"least_correlated_pair": ordered_pairs[0] if ordered_pairs else None,
"most_correlated_pair": ordered_pairs[-1] if ordered_pairs else None,
"timestamp": datetime.now()
}
# Add to analyzer history
self.analyzer.add_regime_entry(result)
# Print results
self.print_results(result, correlation_matrix)
return result
async def main():
"""Main entry point"""
app = MarketRegimeApp()
try:
# Run single detection (will auto-initialize symbols)
result = await app.run_single_detection()
except Exception as e:
print(f"Error during execution: {e}")
return
if result:
# Optionally save results
with open(f"regime_result_{datetime.now().strftime('%Y%m%d_%H%M%S')}.json", "w") as f:
json.dump({
"regime": result["regime"].value,
"up_ratio": result["up_ratio"],
"down_ratio": result["down_ratio"],
"total_symbols": result["total_symbols"],
"correlation_symbols": result["correlation_symbols"],
"direction_symbols": result["direction_symbols"],
"timestamp": result["timestamp"].isoformat()
}, f, indent=2)
print(f"\nResults saved to file.")
if __name__ == "__main__":
asyncio.run(main())
End of Complete Verbatim Conversation Record