Skip to content

Commit 32f203e

Browse files
v3.0.2
Signed-off-by: Dinger <quantdinger@gmail.com>
1 parent 8b9cb89 commit 32f203e

81 files changed

Lines changed: 1822 additions & 205 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

‎.gitignore‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,12 @@ backend_api_python/dist/
6969
backend_api_python/data/quantdinger.db
7070
backend_api_python/data/memory/
7171

72+
# ========================
73+
# i18n tooling
74+
# ========================
75+
scripts/.i18n-cache/
76+
QuantDinger-Vue-src/src/locales/lang/*.bak
77+
7278
# ========================
7379
# Docker
7480
# ========================

‎README.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121

2222
<p>
2323
<a href="LICENSE"><img src="https://img.shields.io/badge/License-Apache%202.0-blue.svg?style=flat-square&logo=apache" alt="License"></a>
24-
<img src="https://img.shields.io/badge/Version-3.0.1-orange?style=flat-square" alt="Version">
24+
<img src="https://img.shields.io/badge/Version-3.0.2-orange?style=flat-square" alt="Version">
2525
<img src="https://img.shields.io/badge/Python-3.10%2B%20%7C%20Docker%20image%203.12-3776AB?style=flat-square&logo=python&logoColor=white" alt="Python">
2626
<img src="https://img.shields.io/badge/Docker-Compose%20Ready-2496ED?style=flat-square&logo=docker&logoColor=white" alt="Docker">
2727
<img src="https://img.shields.io/badge/Frontend-Prebuilt-1f8b4c?style=flat-square" alt="Frontend">

‎backend_api_python/app.zip‎

1.85 MB
Binary file not shown.

‎backend_api_python/app/data_sources/crypto.py‎

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -272,10 +272,23 @@ def get_kline(
272272

273273
# 过滤和限制
274274
klines = self.filter_and_limit(klines, limit, before_time)
275-
275+
276276
# 记录结果
277277
self.log_result(symbol, klines, timeframe)
278-
278+
279+
# Concise trace so backtest logs can correlate requested window with actual window
280+
if klines:
281+
try:
282+
from datetime import datetime as _dt
283+
first_ts = _dt.utcfromtimestamp(klines[0]['time']).isoformat()
284+
last_ts = _dt.utcfromtimestamp(klines[-1]['time']).isoformat()
285+
logger.info(
286+
f"[CryptoKline] {symbol} {timeframe} returned {len(klines)} candles, "
287+
f"utc_range={first_ts}~{last_ts}, limit={limit}, before_time={before_time}"
288+
)
289+
except Exception:
290+
pass
291+
279292
except Exception as e:
280293
logger.error(f"Failed to fetch crypto K-lines {symbol}: {str(e)}")
281294
import traceback

‎backend_api_python/app/routes/backtest.py‎

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -237,8 +237,15 @@ def run_backtest():
237237
'msg': f'Backtest range exceeds limit: timeframe {timeframe} supports up to {max_range_text} ({max_days} days), but you selected {days_diff} days',
238238
'data': None
239239
}), 400
240-
241-
240+
241+
# Explicit audit log so we can always trace exactly which window the user asked for.
242+
logger.info(
243+
f"[BacktestRequest] user={user_id} indicator={indicator_id} {market}:{symbol} "
244+
f"tf={timeframe} range=[{start_date_str} ~ {end_date_str}] ({days_diff}d) "
245+
f"capital={initial_capital} leverage={leverage} direction={trade_direction} "
246+
f"mtf={enable_mtf}"
247+
)
248+
242249
# 执行回测(支持多时间框架高精度回测)
243250
# 加密货币市场且启用MTF时,使用多时间框架回测
244251
if enable_mtf and market.lower() in ['crypto', 'cryptocurrency']:

‎backend_api_python/app/routes/community.py‎

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,43 @@ def purchase_indicator(indicator_id: int):
110110
return jsonify({'code': 0, 'msg': str(e), 'data': None}), 500
111111

112112

113+
@community_bp.route("/indicators/<int:indicator_id>/sync", methods=["POST"])
114+
@login_required
115+
def sync_purchased_indicator(indicator_id: int):
116+
"""
117+
同步已购买指标的最新代码
118+
119+
适用场景:
120+
发布者在上架后又更新了指标代码,已购用户需要
121+
手动拉取最新版本到自己的本地副本。
122+
123+
前置条件:
124+
- 调用者必须已购买该指标
125+
- 原始指标仍处于已发布状态
126+
"""
127+
try:
128+
service = get_community_service()
129+
success, message, data = service.sync_purchased_indicator(
130+
buyer_id=g.user_id,
131+
indicator_id=indicator_id
132+
)
133+
134+
if success:
135+
return jsonify({'code': 1, 'msg': message, 'data': data})
136+
else:
137+
# 不同失败场景给到可区分的 http 状态,便于前端处理
138+
status = 400
139+
if message in ('indicator_not_found', 'indicator_unpublished', 'local_copy_not_found'):
140+
status = 404
141+
elif message == 'not_purchased':
142+
status = 403
143+
return jsonify({'code': 0, 'msg': message, 'data': data}), status
144+
145+
except Exception as e:
146+
logger.error(f"sync_purchased_indicator failed: {e}")
147+
return jsonify({'code': 0, 'msg': str(e), 'data': None}), 500
148+
149+
113150
@community_bp.route("/my-purchases", methods=["GET"])
114151
@login_required
115152
def get_my_purchases():

‎backend_api_python/app/routes/strategy.py‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -373,6 +373,13 @@ def run_strategy_backtest():
373373
'data': None
374374
}), 400
375375

376+
logger.info(
377+
f"[StrategyBacktestRequest] user={user_id} strategy={strategy_id} "
378+
f"{snapshot.get('market') or ''}:{snapshot.get('symbol') or ''} "
379+
f"tf={timeframe} range=[{start_date_str} ~ {end_date_str}] ({days_diff}d) "
380+
f"run_type={snapshot.get('run_type') or ''}"
381+
)
382+
376383
svc = get_backtest_service()
377384
result = svc.run_strategy_snapshot(snapshot, start_date=start_date, end_date=end_date)
378385
run_id = svc.persist_run(

0 commit comments

Comments
 (0)