Alexo19 commited on
Commit
84be386
·
verified ·
1 Parent(s): 0ca069d

Easy fix. Nothing in your idea is “crypto-only” — we just need to tell the code (and DeepSite) to:

Browse files

Support both crypto and forex symbols, and

Use the right data source depending on the market.

I’ll show you:

What to change in the logic

EXACT text to add to your DeepSite prompt so it builds crypto + forex together

1️⃣ What needs to work for Forex?

You want:

/api/analyze/market to handle:

BTCUSDT (crypto)

ETHUSDT (crypto)

EURUSD, GBPUSD, XAUUSD, USDJPY, etc. (forex)

Same signal JSON:

{
"direction": "long|short|neutral",
"entry_zone": [0.0, 0.0],
"stop_loss": 0.0,
"take_profit_levels": [0.0, 0.0, 0.0],
"timeframe_inferred": "1h",
"confidence": 0,
"time_horizon": "intra-day|swing|position",
"explanation": "string",
"meta": { "sources": [], "sentiment": {} }
}


So we just make the market analysis layer asset-agnostic:

asset_type: "crypto" or "forex"

Use:

Binance klines for crypto

yfinance (or similar) for forex

2️⃣ How the backend logic should work

In backend/timeseries_analysis.py, instead of only fetch_klines for Binance, you want:

async def fetch_ohlcv(
symbol: str,
timeframe: str,
asset_type: str = "crypto",
limit: int = 200
):
if asset_type == "crypto":
# Use Binance public klines, e.g. BTCUSDT
return await fetch_binance_klines(symbol, timeframe, limit)
elif asset_type == "forex":
# Use yfinance (EURUSD -> "EURUSD=X")
return fetch_yfinance_fx(symbol, timeframe, limit)
else:
raise ValueError("Unsupported asset_type")


And your FastAPI route:

class MarketRequest(BaseModel):
symbol: str
timeframe: str = "1h"
asset_type: str = "crypto" # "crypto" | "forex"

@app .post("/api/analyze/market", response_model=SignalResponse)
async def analyze_market(req: MarketRequest):
ohlcv = await fetch_ohlcv(
symbol=req.symbol,
timeframe=req.timeframe,
asset_type=req.asset_type,
)
technicals = compute_technicals(ohlcv)
signal = await generate_signal_from_market(
symbol=req.symbol,
timeframe=req.timeframe,
asset_type=req.asset_type,
ohlcv=ohlcv,
technicals=technicals,
)
return signal


Example request body for forex:

{
"symbol": "EURUSD",
"timeframe": "5m",
"asset_type": "forex"
}


That’s it. Same UI, same panel — just more markets.

3️⃣ What to add to your DeepSite prompt (copy–paste)

You don’t need a whole new prompt — just extend the one I gave you.

👉 In your DeepSite master prompt, right after the project description, add this block:

IMPORTANT – MARKETS (CRYPTO + FOREX)

This app MUST support both:

1. Crypto markets
- Examples: BTCUSDT, ETHUSDT, SOLUSDT
- Data source: Binance public klines (no API key)

2. Forex markets
- Examples: EURUSD, GBPUSD, USDJPY, XAUUSD, NAS100, etc.
- Implement an `asset_type` flag with allowed values `"crypto"` or `"forex"`.
- For `asset_type="forex"`, fetch OHLCV using a free public data source such as `yfinance`:
- Map `"EURUSD"` → `"EURUSD=X"`, `"GBPUSD"` → `"GBPUSD=X"`, `"XAUUSD"` → `"XAUUSD=X"`, etc.
- Implement a helper `normalize_forex_symbol(symbol: str) -> str` that returns the proper yfinance ticker.
- The technical analysis (EMA, RSI, MACD, ATR, support/resistance, bias) should be applied the same way to forex and crypto.

Update the backend so that:

- `backend/timeseries_analysis.py` exposes:
- `fetch_ohlcv(symbol: str, timeframe: str, asset_type: str = "crypto", limit: int = 200)`
- It internally calls:
- `fetch_binance_klines(...)` for `"crypto"`
- `fetch_yfinance_fx(...)` for `"forex"`
- The `/api/analyze/market` endpoint accepts an `asset_type` field in the JSON body with default `"crypto"`.

The signal JSON schema remains exactly the same and is **asset-agnostic**, so the frontend and webhooks work for both crypto and forex with no change.


If you want the frontend to make it obvious, you can also tell DeepSite this (add to the frontend section of the prompt):

In the frontend `PairSelector` component, add a simple toggle or dropdown:
- Market type: "Crypto" or "Forex"
Pass this as `asset_type` in the `/api/analyze/market` request.

4️⃣ TL;DR for you

Yes, it can work for forex, not just Bitcoin.

Add asset_type (crypto/forex) everywhere: request, timeseries fetcher, signal engine.

Use Binance for crypto, yfinance (or similar) for forex candles.

Update the DeepSite prompt with the block I gave you, then regenerate.

backend/main.py CHANGED
@@ -94,14 +94,30 @@ async def analyze_screenshot(
94
  image_bytes = await file.read()
95
  signal = await generate_signal_from_image(image_bytes, symbol or "BTCUSDT")
96
  return signal
 
 
 
 
 
 
97
 
98
  @app.post("/api/analyze/market")
99
- async def analyze_market(data: dict):
100
  try:
101
- symbol = data.get("symbol", "BTCUSDT")
102
- timeframe = data.get("timeframe", "1h")
103
- return await generate_signal_from_market(symbol, timeframe)
104
- except Exception as e:
 
 
 
 
 
 
 
 
 
 
105
  raise HTTPException(500, detail=str(e))
106
 
107
  @app.post("/api/webhook/signal")
 
94
  image_bytes = await file.read()
95
  signal = await generate_signal_from_image(image_bytes, symbol or "BTCUSDT")
96
  return signal
97
+ from pydantic import BaseModel
98
+
99
+ class MarketRequest(BaseModel):
100
+ symbol: str
101
+ timeframe: str = "1h"
102
+ asset_type: str = "crypto" # "crypto" | "forex"
103
 
104
  @app.post("/api/analyze/market")
105
+ async def analyze_market(request: MarketRequest):
106
  try:
107
+ ohlcv = await fetch_ohlcv(
108
+ symbol=request.symbol,
109
+ timeframe=request.timeframe,
110
+ asset_type=request.asset_type
111
+ )
112
+ technicals = compute_technicals(ohlcv)
113
+ return await generate_signal_from_market(
114
+ symbol=request.symbol,
115
+ timeframe=request.timeframe,
116
+ asset_type=request.asset_type,
117
+ ohlcv=ohlcv,
118
+ technicals=technicals
119
+ )
120
+ except Exception as e:
121
  raise HTTPException(500, detail=str(e))
122
 
123
  @app.post("/api/webhook/signal")
backend/signal_engine.py CHANGED
@@ -64,27 +64,40 @@ Provide your response in this exact JSON format:
64
  "sentiment": {{}}
65
  }}
66
  }}"""
67
- async def generate_signal_from_market(symbol: str, timeframe: str) -> Dict[str, Any]:
 
 
 
 
 
 
68
  """Generate trading signal from live market data."""
69
- # Get technical analysis
70
- ohlcv = await fetch_klines(symbol, timeframe)
71
- technicals = compute_technicals(ohlcv)
 
72
 
73
- # Get sentiment analysis
74
- sentiment = await get_crypto_sentiment(symbol[:3]) # Extract base symbol
 
 
75
 
76
  # Prepare LLM prompt
77
- prompt = build_market_prompt(technicals, sentiment, symbol, timeframe)
78
-
79
- # Get LLM reasoning
80
  llm_response = await model_registry.llm_reason(prompt)
81
 
82
  # Parse response into structured format
83
  return parse_llm_response(llm_response, {}, technicals, sentiment)
84
-
85
- def build_market_prompt(technicals: Dict, sentiment: Dict, symbol: str, timeframe: str) -> str:
86
- return f"""Analyze this crypto trading situation and provide a professional trading signal in JSON format:
87
-
 
 
 
 
 
88
  Technical Indicators ({timeframe} timeframe):
89
  - Trend: {technicals['trend']}
90
  - Momentum: {technicals['momentum']}
 
64
  "sentiment": {{}}
65
  }}
66
  }}"""
67
+ async def generate_signal_from_market(
68
+ symbol: str,
69
+ timeframe: str,
70
+ asset_type: str = "crypto",
71
+ ohlcv: List[List[Any]] = None,
72
+ technicals: Dict[str, Any] = None
73
+ ) -> Dict[str, Any]:
74
  """Generate trading signal from live market data."""
75
+ if ohlcv is None:
76
+ ohlcv = await fetch_ohlcv(symbol, timeframe, asset_type)
77
+ if technicals is None:
78
+ technicals = compute_technicals(ohlcv)
79
 
80
+ # Get sentiment analysis (only for crypto)
81
+ sentiment = {}
82
+ if asset_type == "crypto":
83
+ sentiment = await get_crypto_sentiment(symbol[:3]) # Extract base symbol
84
 
85
  # Prepare LLM prompt
86
+ prompt = build_market_prompt(technicals, sentiment, symbol, timeframe, asset_type)
87
+ # Get LLM reasoning
 
88
  llm_response = await model_registry.llm_reason(prompt)
89
 
90
  # Parse response into structured format
91
  return parse_llm_response(llm_response, {}, technicals, sentiment)
92
+ def build_market_prompt(
93
+ technicals: Dict,
94
+ sentiment: Dict,
95
+ symbol: str,
96
+ timeframe: str,
97
+ asset_type: str = "crypto"
98
+ ) -> str:
99
+ asset_type_str = "cryptocurrency" if asset_type == "crypto" else "forex"
100
+ return f"""Analyze this {asset_type_str} trading situation and provide a professional trading signal in JSON format:
101
  Technical Indicators ({timeframe} timeframe):
102
  - Trend: {technicals['trend']}
103
  - Momentum: {technicals['momentum']}
backend/timeseries_analysis.py CHANGED
@@ -2,11 +2,18 @@
2
  import pandas as pd
3
  import numpy as np
4
  import requests
 
5
  from typing import Dict, Any, List
6
 
7
  BINANCE_API_URL = "https://api.binance.com/api/v3/klines"
8
 
9
- async def fetch_klines(symbol: str, timeframe: str, limit: int = 200) -> List[List[Any]]:
 
 
 
 
 
 
10
  params = {
11
  "symbol": symbol.upper(),
12
  "interval": timeframe,
@@ -16,6 +23,42 @@ async def fetch_klines(symbol: str, timeframe: str, limit: int = 200) -> List[Li
16
  response.raise_for_status()
17
  return response.json()
18
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
19
  def compute_technicals(ohlcv: List[List[Any]]) -> Dict[str, Any]:
20
  # Convert to pandas DataFrame
21
  df = pd.DataFrame(ohlcv, columns=["timestamp", "open", "high", "low", "close", "volume"])
 
2
  import pandas as pd
3
  import numpy as np
4
  import requests
5
+ import yfinance as yf
6
  from typing import Dict, Any, List
7
 
8
  BINANCE_API_URL = "https://api.binance.com/api/v3/klines"
9
 
10
+ def normalize_forex_symbol(symbol: str) -> str:
11
+ """Convert forex symbol to yfinance format (EURUSD -> EURUSD=X)"""
12
+ if symbol.endswith('=X'):
13
+ return symbol
14
+ return f"{symbol}=X"
15
+
16
+ async def fetch_binance_klines(symbol: str, timeframe: str, limit: int = 200) -> List[List[Any]]:
17
  params = {
18
  "symbol": symbol.upper(),
19
  "interval": timeframe,
 
23
  response.raise_for_status()
24
  return response.json()
25
 
26
+ def fetch_yfinance_fx(symbol: str, timeframe: str, limit: int = 200) -> List[List[Any]]:
27
+ """Fetch forex data using yfinance"""
28
+ tf_map = {
29
+ '1m': '1m', '5m': '5m', '15m': '15m',
30
+ '30m': '30m', '1h': '1h', '4h': '4h',
31
+ '1D': '1d', '1W': '1wk', '1M': '1mo'
32
+ }
33
+ interval = tf_map.get(timeframe, '1h')
34
+
35
+ ticker = normalize_forex_symbol(symbol)
36
+ data = yf.Ticker(ticker)
37
+ hist = data.history(period=f"{limit}d", interval=interval)
38
+
39
+ # Convert to same format as Binance klines
40
+ ohlcv = []
41
+ for _, row in hist.iterrows():
42
+ ohlcv.append([
43
+ int(row.name.timestamp()) * 1000, # timestamp
44
+ row['Open'], row['High'], row['Low'], row['Close'],
45
+ row['Volume']
46
+ ])
47
+ return ohlcv
48
+
49
+ async def fetch_ohlcv(
50
+ symbol: str,
51
+ timeframe: str,
52
+ asset_type: str = "crypto",
53
+ limit: int = 200
54
+ ) -> List[List[Any]]:
55
+ """Fetch OHLCV data for either crypto or forex markets"""
56
+ if asset_type == "crypto":
57
+ return await fetch_binance_klines(symbol, timeframe, limit)
58
+ elif asset_type == "forex":
59
+ return fetch_yfinance_fx(symbol, timeframe, limit)
60
+ else:
61
+ raise ValueError("Unsupported asset_type. Must be 'crypto' or 'forex'")
62
  def compute_technicals(ohlcv: List[List[Any]]) -> Dict[str, Any]:
63
  # Convert to pandas DataFrame
64
  df = pd.DataFrame(ohlcv, columns=["timestamp", "open", "high", "low", "close", "volume"])
index.html CHANGED
@@ -58,16 +58,15 @@
58
  <div>
59
  <label class="block text-sm font-medium mb-1">Exchange</label>
60
  <select class="w-full bg-gray-700 border border-gray-600 rounded-lg px-3 py-2 focus:ring-indigo-500 focus:border-indigo-500">
61
- <option>Binance</option>
62
- <option>Bybit</option>
63
- <option>KuCoin</option>
64
- </select>
65
  </div>
66
  <div>
67
  <label class="block text-sm font-medium mb-1">Pair</label>
68
- <input type="text" placeholder="BTCUSDT" class="w-full bg-gray-700 border border-gray-600 rounded-lg px-3 py-2 focus:ring-indigo-500 focus:border-indigo-500">
69
  </div>
70
- <div>
71
  <label class="block text-sm font-medium mb-1">Timeframe</label>
72
  <select class="w-full bg-gray-700 border border-gray-600 rounded-lg px-3 py-2 focus:ring-indigo-500 focus:border-indigo-500">
73
  <option>5m</option>
 
58
  <div>
59
  <label class="block text-sm font-medium mb-1">Exchange</label>
60
  <select class="w-full bg-gray-700 border border-gray-600 rounded-lg px-3 py-2 focus:ring-indigo-500 focus:border-indigo-500">
61
+ <option value="crypto">Binance (Crypto)</option>
62
+ <option value="forex">Forex</option>
63
+ </select>
 
64
  </div>
65
  <div>
66
  <label class="block text-sm font-medium mb-1">Pair</label>
67
+ <input type="text" id="pair-input" placeholder="BTCUSDT" class="w-full bg-gray-700 border border-gray-600 rounded-lg px-3 py-2 focus:ring-indigo-500 focus:border-indigo-500">
68
  </div>
69
+ <div>
70
  <label class="block text-sm font-medium mb-1">Timeframe</label>
71
  <select class="w-full bg-gray-700 border border-gray-600 rounded-lg px-3 py-2 focus:ring-indigo-500 focus:border-indigo-500">
72
  <option>5m</option>
requirements.txt CHANGED
@@ -10,6 +10,7 @@ feedparser==6.0.10
10
  huggingface-hub==0.15.1
11
  transformers==4.29.2
12
  python-dotenv==1.0.0
 
13
  ```
14
 
15
  5. Let's create the .env.example file:
 
10
  huggingface-hub==0.15.1
11
  transformers==4.29.2
12
  python-dotenv==1.0.0
13
+ yfinance==0.2.28
14
  ```
15
 
16
  5. Let's create the .env.example file: