Skip to content

Commit cf58ff4

Browse files
committed
v2.2.1
Signed-off-by: TIANHE <TIANHE@GMAIL.COM>
1 parent d92d4c5 commit cf58ff4

31 files changed

+138
-64
lines changed

backend_api_python/app/routes/global_market.py

Lines changed: 45 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1656,6 +1656,12 @@ def _analyze_opportunities_crypto(opportunities: list):
16561656
crypto_data = _fetch_crypto_prices()
16571657
if crypto_data:
16581658
_set_cached("crypto_prices", crypto_data)
1659+
1660+
if not crypto_data:
1661+
logger.warning("_analyze_opportunities_crypto: No crypto data available")
1662+
return
1663+
1664+
logger.debug(f"_analyze_opportunities_crypto: Analyzing {len(crypto_data)} crypto coins")
16591665

16601666
for coin in (crypto_data or [])[:20]:
16611667
change = _safe_float(coin.get("change_24h", 0))
@@ -1669,12 +1675,13 @@ def _analyze_opportunities_crypto(opportunities: list):
16691675
reason = ""
16701676
impact = "neutral"
16711677

1678+
# Lower thresholds to show more opportunities
16721679
if change > 15:
16731680
signal = "overbought"
16741681
strength = "strong"
16751682
reason = f"24h涨幅{change:.1f}%,7日涨幅{change_7d:.1f}%,短期超买风险"
16761683
impact = "bearish"
1677-
elif change > 8:
1684+
elif change > 5: # Lowered from 8 to 5
16781685
signal = "bullish_momentum"
16791686
strength = "medium"
16801687
reason = f"24h涨幅{change:.1f}%,上涨动能强劲"
@@ -1684,7 +1691,7 @@ def _analyze_opportunities_crypto(opportunities: list):
16841691
strength = "strong"
16851692
reason = f"24h跌幅{abs(change):.1f}%,可能超卖反弹"
16861693
impact = "bullish"
1687-
elif change < -8:
1694+
elif change < -5: # Lowered from -8 to -5
16881695
signal = "bearish_momentum"
16891696
strength = "medium"
16901697
reason = f"24h跌幅{abs(change):.1f}%,下跌趋势明显"
@@ -1713,6 +1720,12 @@ def _analyze_opportunities_stocks(opportunities: list):
17131720
stock_data = _fetch_stock_opportunity_prices()
17141721
if stock_data:
17151722
_set_cached("stock_opportunity_prices", stock_data, 3600)
1723+
1724+
if not stock_data:
1725+
logger.warning("_analyze_opportunities_stocks: No stock data available")
1726+
return
1727+
1728+
logger.debug(f"_analyze_opportunities_stocks: Analyzing {len(stock_data)} stocks")
17161729

17171730
for stock in (stock_data or []):
17181731
change = _safe_float(stock.get("change", 0))
@@ -1731,7 +1744,7 @@ def _analyze_opportunities_stocks(opportunities: list):
17311744
strength = "strong"
17321745
reason = f"日涨幅{change:.1f}%,短期涨幅较大,注意回调风险"
17331746
impact = "bearish"
1734-
elif change > 3:
1747+
elif change > 2: # Lowered from 3 to 2
17351748
signal = "bullish_momentum"
17361749
strength = "medium"
17371750
reason = f"日涨幅{change:.1f}%,上涨动能强劲"
@@ -1741,7 +1754,7 @@ def _analyze_opportunities_stocks(opportunities: list):
17411754
strength = "strong"
17421755
reason = f"日跌幅{abs(change):.1f}%,可能超卖反弹"
17431756
impact = "bullish"
1744-
elif change < -3:
1757+
elif change < -2: # Lowered from -3 to -2
17451758
signal = "bearish_momentum"
17461759
strength = "medium"
17471760
reason = f"日跌幅{abs(change):.1f}%,下跌趋势明显"
@@ -1769,6 +1782,12 @@ def _analyze_opportunities_forex(opportunities: list):
17691782
forex_data = _fetch_forex_pairs()
17701783
if forex_data:
17711784
_set_cached("forex_pairs", forex_data, 3600)
1785+
1786+
if not forex_data:
1787+
logger.warning("_analyze_opportunities_forex: No forex data available")
1788+
return
1789+
1790+
logger.debug(f"_analyze_opportunities_forex: Analyzing {len(forex_data)} forex pairs")
17721791

17731792
for pair in (forex_data or []):
17741793
change = _safe_float(pair.get("change", 0))
@@ -1787,7 +1806,7 @@ def _analyze_opportunities_forex(opportunities: list):
17871806
strength = "strong"
17881807
reason = f"日涨幅{change:.2f}%,汇率波动剧烈,注意回调"
17891808
impact = "bearish"
1790-
elif change > 0.8:
1809+
elif change > 0.5: # Lowered from 0.8 to 0.5
17911810
signal = "bullish_momentum"
17921811
strength = "medium"
17931812
reason = f"日涨幅{change:.2f}%,上涨动能较强"
@@ -1797,7 +1816,7 @@ def _analyze_opportunities_forex(opportunities: list):
17971816
strength = "strong"
17981817
reason = f"日跌幅{abs(change):.2f}%,汇率波动剧烈,可能反弹"
17991818
impact = "bullish"
1800-
elif change < -0.8:
1819+
elif change < -0.5: # Lowered from -0.8 to -0.5
18011820
signal = "bearish_momentum"
18021821
strength = "medium"
18031822
reason = f"日跌幅{abs(change):.2f}%,下跌趋势明显"
@@ -1836,17 +1855,34 @@ def trading_opportunities():
18361855
opportunities = []
18371856

18381857
# 1) Crypto
1839-
_analyze_opportunities_crypto(opportunities)
1858+
try:
1859+
_analyze_opportunities_crypto(opportunities)
1860+
crypto_count = len([o for o in opportunities if o.get("market") == "Crypto"])
1861+
logger.info(f"Trading opportunities: found {crypto_count} crypto opportunities")
1862+
except Exception as e:
1863+
logger.error(f"Failed to analyze crypto opportunities: {e}", exc_info=True)
18401864

18411865
# 2) US Stocks
1842-
_analyze_opportunities_stocks(opportunities)
1866+
try:
1867+
_analyze_opportunities_stocks(opportunities)
1868+
stock_count = len([o for o in opportunities if o.get("market") == "USStock"])
1869+
logger.info(f"Trading opportunities: found {stock_count} US stock opportunities")
1870+
except Exception as e:
1871+
logger.error(f"Failed to analyze stock opportunities: {e}", exc_info=True)
18431872

18441873
# 3) Forex
1845-
_analyze_opportunities_forex(opportunities)
1874+
try:
1875+
_analyze_opportunities_forex(opportunities)
1876+
forex_count = len([o for o in opportunities if o.get("market") == "Forex"])
1877+
logger.info(f"Trading opportunities: found {forex_count} forex opportunities")
1878+
except Exception as e:
1879+
logger.error(f"Failed to analyze forex opportunities: {e}", exc_info=True)
18461880

18471881
# Sort by absolute change descending
18481882
opportunities.sort(key=lambda x: abs(x.get("change_24h", 0)), reverse=True)
18491883

1884+
logger.info(f"Trading opportunities: total {len(opportunities)} opportunities found (Crypto: {len([o for o in opportunities if o.get('market') == 'Crypto'])}, USStock: {len([o for o in opportunities if o.get('market') == 'USStock'])}, Forex: {len([o for o in opportunities if o.get('market') == 'Forex'])})")
1885+
18501886
_set_cached("trading_opportunities", opportunities, 3600)
18511887

18521888
return jsonify({"code": 1, "msg": "success", "data": opportunities})

backend_api_python/app/routes/quick_trade.py

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -830,6 +830,18 @@ def close_position():
830830
avg_fill = float(getattr(result, "avg_price", 0) or 0)
831831
raw = getattr(result, "raw", {}) or {}
832832

833+
# ---- calculate USDT amount for recording ----
834+
# Convert base asset quantity to USDT amount for consistent recording
835+
# amount (USDT) = base_qty * price
836+
usdt_amount = actual_close_size * avg_fill if avg_fill > 0 else 0
837+
# If price is not available, try to use entry price or mark price as fallback
838+
if usdt_amount <= 0:
839+
entry_price = float(position.get("entry_price") or 0)
840+
mark_price = float(position.get("mark_price") or 0)
841+
fallback_price = mark_price if mark_price > 0 else entry_price
842+
if fallback_price > 0:
843+
usdt_amount = actual_close_size * fallback_price
844+
833845
# ---- record trade ----
834846
trade_id = _record_quick_trade(
835847
user_id=user_id,
@@ -838,7 +850,7 @@ def close_position():
838850
symbol=symbol,
839851
side="sell" if position_side == "long" else "buy", # Opposite of position side
840852
order_type="market",
841-
amount=actual_close_size, # Record position size
853+
amount=usdt_amount, # Record USDT amount, not base asset quantity
842854
price=avg_fill,
843855
leverage=float(position.get("leverage") or 1),
844856
market_type=market_type,

backend_api_python/app/services/pending_order_worker.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,19 @@ def _sync_positions_best_effort(self, target_strategy_id: Optional[int] = None)
214214
market_type = str(market_type or "swap").strip().lower()
215215
if market_type in ("futures", "future", "perp", "perpetual"):
216216
market_type = "swap"
217+
218+
# Get strategy's trading symbol(s) to filter positions
219+
# Only sync positions for symbols that this strategy actually trades
220+
strategy_symbol = (sc.get("symbol") or "").strip()
221+
trading_config = sc.get("trading_config") or {}
222+
symbol_list = trading_config.get("symbol_list") or []
223+
# Normalize symbol list: convert to set for fast lookup
224+
allowed_symbols = set()
225+
if strategy_symbol:
226+
allowed_symbols.add(strategy_symbol.upper())
227+
for sym in symbol_list:
228+
if sym and isinstance(sym, str):
229+
allowed_symbols.add(sym.strip().upper())
217230

218231
# Lazy import MT5 here to allow elif chain later
219232
global MT5Client
@@ -500,10 +513,23 @@ def _sync_positions_best_effort(self, target_strategy_id: Optional[int] = None)
500513
to_update.append({"id": rid, "size": exch_qty, "entry_price": exch_price})
501514

502515
# [New Feature] Detect positions that exist on exchange but not in local DB, and insert them.
516+
# IMPORTANT: Only insert positions for symbols that this strategy actually trades
517+
# This prevents syncing positions from quick trade or other sources
503518
to_insert: List[Dict[str, Any]] = []
504519
local_symbols_sides = {(str(r.get("symbol") or "").strip(), str(r.get("side") or "").strip().lower()) for r in plist}
505520

506521
for _sym, _sides_map in exch_size.items():
522+
# Filter: only sync positions for symbols that this strategy trades
523+
# If strategy has no symbol configured, skip auto-insert to prevent syncing quick trade positions
524+
_sym_upper = _sym.strip().upper()
525+
if allowed_symbols and _sym_upper not in allowed_symbols:
526+
logger.debug(f"[PositionSync] Skipping {_sym}: not in strategy's symbol list (strategy trades: {allowed_symbols})")
527+
continue
528+
elif not allowed_symbols:
529+
# Strategy has no symbol configured - skip to prevent syncing unrelated positions
530+
logger.debug(f"[PositionSync] Skipping {_sym}: strategy has no symbol configured (preventing quick trade position sync)")
531+
continue
532+
507533
for _side, _qty in _sides_map.items():
508534
if _qty > 1e-12 and (_sym, _side) not in local_symbols_sides:
509535
# Exchange has this position but local DB does not

frontend/dist/css/243.0b55d10c.css

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

frontend/dist/css/254.3729a915.css

Lines changed: 0 additions & 1 deletion
This file was deleted.

frontend/dist/css/346.a278841f.css

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

frontend/dist/css/378.3729a915.css

Lines changed: 0 additions & 1 deletion
This file was deleted.

frontend/dist/css/771.17b34efc.css

Lines changed: 0 additions & 1 deletion
This file was deleted.

frontend/dist/css/808.0b55d10c.css

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

frontend/dist/css/870.a278841f.css

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)