Retry incomplete SET bars and rebuild stale MT5 signals
This commit is contained in:
@@ -342,3 +342,9 @@ powershell.exe -NoProfile -ExecutionPolicy Bypass -File .\mt5_app\install-autost
|
||||
- ไฟล์ `data/supervisor.stop` เป็นเครื่องหมายหยุดที่คงอยู่ข้ามรอบ Task จึงไม่ถูกล้างเองทุกครั้งที่ตัวดูแลเริ่ม ติดตั้ง/เปิดผ่าน `install-autostart.ps1` จะล้างเครื่องหมายโดยตั้งใจ ส่วน `-Remove` ปิด trigger ก่อนหยุดและถอด Task
|
||||
|
||||
ยังไม่ทราบว่าโปรแกรมใดเปิด/ล็อกไฟล์ในจังหวะนั้น การแก้ไม่เปลี่ยนสิทธิ์ไฟล์หรือใช้ Administrator และไม่ล้างฐานข้อมูลบัญชี/คำสั่งเดิม
|
||||
|
||||
### ตรวจความครบของข้อมูล SET หลังเปิดแอปกลับ
|
||||
|
||||
ระหว่างกู้แอปวันที่ 29 ต.ค. พบว่าเว็บและ MT5 ยังเชื่อมต่อได้ แต่สัญญาณคำนวณต่อไม่ได้เพราะ SET ใน SQLite ถึง 27 ต.ค. ขณะที่หุ้นถึง 28 ต.ค. แม้ MT5 มี SET วันที่ 28 แล้ว สาเหตุคือแอปจำวันที่ร้องขอเป็นวันที่โหลดสำเร็จ แล้วข้าม SET ในรอบถัดไป
|
||||
|
||||
แก้ให้ตรวจวันที่แท่ง SET ที่เก็บจริงก่อนใช้ cache หากยังไม่ถึงวันเป้าหมายจะดึง SET ใหม่และเก็บ latest_day ถ้าแหล่งข้อมูลยังไม่ครบจะลองใหม่ตามรอบข้อมูลเดิม หากสัญญาณเก่ากว่าข้อมูลที่ต้องใช้จะคำนวณใหม่ และ dashboard จะขึ้นรอข้อมูลแทนแผนเก่า โดยไม่เปลี่ยนกฎ Donchian/EMA หรือเติมดัชนีที่ไม่มีข้อมูลจริงเอง
|
||||
|
||||
@@ -43,7 +43,8 @@ def plain(value):
|
||||
|
||||
def download_history(broker, store, settings, progress, *, force=False):
|
||||
through = settings.closed_through()
|
||||
if store.get('history_checked_through') == through and not force:
|
||||
benchmark_ready = store.last_bar_day('SET', through) == through
|
||||
if store.get('history_checked_through') == through and benchmark_ready and not force:
|
||||
progress('history', 'ใช้ประวัติ MT5 ที่เก็บไว้แล้ว', 1, 1)
|
||||
return store.get('history_download', {})
|
||||
symbols = [s.name for s in broker.symbols()
|
||||
@@ -57,8 +58,11 @@ def download_history(broker, store, settings, progress, *, force=False):
|
||||
progress('history', f'อ่าน D1 {symbol} · {number}/{len(symbols)}', number, len(symbols))
|
||||
try:
|
||||
symbol_state = store.get('history_symbol:' + symbol, {})
|
||||
if (symbol_state.get('through') == through
|
||||
or (symbol in previous and previous_record.get('through') == through)) and not force:
|
||||
cached = (symbol_state.get('through') == through
|
||||
or (symbol in previous and previous_record.get('through') == through))
|
||||
# A successful download request is not proof the benchmark reached
|
||||
# the requested session. Retry SET until the actual D1 bar arrives.
|
||||
if cached and not force and (symbol != 'SET' or benchmark_ready):
|
||||
successful.append(symbol)
|
||||
if symbol in previous_record.get('zero_real_volume', []):
|
||||
zero_volume.append(symbol)
|
||||
@@ -69,8 +73,8 @@ def download_history(broker, store, settings, progress, *, force=False):
|
||||
rates = broker.history(symbol, count)
|
||||
rows = []
|
||||
for r in rates:
|
||||
# D1 timestamps label the exchange session. MT5 stores them as
|
||||
# UTC; do not use the workstation timezone to shift the date.
|
||||
# D1 calendar dates label broker sessions; keep that raw date.
|
||||
# Intraday quote/server-clock conversion must not shift D1 labels.
|
||||
day = datetime.fromtimestamp(int(r['time']), timezone.utc).date().isoformat()
|
||||
prices = [float(r[c]) for c in ('open', 'high', 'low', 'close')]
|
||||
if day < settings.warmup_start or day > through:
|
||||
@@ -83,7 +87,11 @@ def download_history(broker, store, settings, progress, *, force=False):
|
||||
if symbol != 'SET' and all(r[6] <= 0 for r in rows):
|
||||
zero_volume.append(symbol)
|
||||
store.save_bars(rows)
|
||||
store.put('history_symbol:' + symbol, {'through': through, 'rows': len(rows), 'checked_at': now_iso()})
|
||||
latest_day = max(r[1] for r in rows)
|
||||
store.put('history_symbol:' + symbol, {'through': through, 'latest_day': latest_day,
|
||||
'rows': len(rows), 'checked_at': now_iso()})
|
||||
if symbol == 'SET' and latest_day != through:
|
||||
raise ValueError(f'SET D1 ล่าสุด {latest_day}; ต้องถึง {through} จะลองดึงใหม่ในรอบถัดไป')
|
||||
successful.append(symbol)
|
||||
except Exception as exc:
|
||||
failures.append({'symbol': symbol, 'error': str(exc)})
|
||||
|
||||
@@ -247,16 +247,23 @@ class Desk:
|
||||
last_attempt = previous.get('checked_at')
|
||||
retry_due = (not last_attempt or time.time() - datetime.fromisoformat(last_attempt).timestamp() >= 600)
|
||||
needs_new_day = previous.get('through') != self.settings.closed_through()
|
||||
incomplete = self.store.get('history_checked_through') != self.settings.closed_through()
|
||||
if research or not model or needs_new_day or (incomplete and retry_due):
|
||||
incomplete = (self.store.get('history_checked_through') != self.settings.closed_through()
|
||||
or self.store.last_bar_day('SET', self.settings.closed_through())
|
||||
!= self.settings.closed_through())
|
||||
model_due = model.get('signal_as_of') != self.settings.closed_through()
|
||||
if research or not model or needs_new_day or ((incomplete or model_due) and retry_due):
|
||||
before = self.store.bar_summary()
|
||||
download_history(self.broker, self.store, self.settings, self.progress)
|
||||
if research or not model or needs_new_day or self.store.bar_summary() != before:
|
||||
if research or not model or needs_new_day or model_due or self.store.bar_summary() != before:
|
||||
model = run_research(self.store, self.settings, self.progress)
|
||||
snapshot = self.broker.snapshot()
|
||||
self.progress('quotes', 'อ่านราคาเสนอซื้อขายของหุ้นในแผน')
|
||||
self.update_quotes(snapshot, model)
|
||||
self.store.put('job', {'running': False, 'stage': 'complete', 'message': 'พร้อมใช้งาน', 'updated_at': now_iso()})
|
||||
pending = model.get('signal_as_of') != self.settings.closed_through()
|
||||
message = (f'พอร์ตอัปเดตแล้ว แต่สัญญาณถึง {model.get("signal_as_of", "ยังไม่มี")} '
|
||||
f'รอข้อมูล/คำนวณถึง {self.settings.closed_through()}' if pending else 'พร้อมใช้งาน')
|
||||
self.store.put('job', {'running': False, 'stage': 'waiting_data' if pending else 'complete',
|
||||
'message': message, 'updated_at': now_iso()})
|
||||
except Exception as exc:
|
||||
self.log.exception('refresh_failed')
|
||||
self.store.put('connection_error', {'message': str(exc), 'at': now_iso()})
|
||||
@@ -274,6 +281,7 @@ class Desk:
|
||||
job = self.store.get('job', {})
|
||||
plan = make_plan(snap, model, self.store.skipped(day), self.settings)
|
||||
if (not model.get('data_quality', {}).get('calendar_source')
|
||||
or model.get('signal_as_of') != self.settings.closed_through()
|
||||
or (job.get('running') and job.get('stage') in ('history', 'archive', 'signals', 'comparison'))):
|
||||
for row in plan['rows']:
|
||||
row.update(action='WAIT', quantity=0, reason='รอการตรวจปฏิทินข้อมูล MT5 ให้ครบ')
|
||||
|
||||
Reference in New Issue
Block a user