@mulsok/traders-client 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (119) hide show
  1. package/README.md +103 -0
  2. package/bin/cli.js +160 -0
  3. package/bin/postinstall.js +57 -0
  4. package/bin/preuninstall.js +36 -0
  5. package/dist/server/broker/kiwoom/cache.js +86 -0
  6. package/dist/server/broker/kiwoom/cache.js.map +1 -0
  7. package/dist/server/broker/kiwoom/client.js +256 -0
  8. package/dist/server/broker/kiwoom/client.js.map +1 -0
  9. package/dist/server/broker/kiwoom/endpoints/_helpers.js +61 -0
  10. package/dist/server/broker/kiwoom/endpoints/_helpers.js.map +1 -0
  11. package/dist/server/broker/kiwoom/endpoints/account.js +448 -0
  12. package/dist/server/broker/kiwoom/endpoints/account.js.map +1 -0
  13. package/dist/server/broker/kiwoom/endpoints/detail.js +118 -0
  14. package/dist/server/broker/kiwoom/endpoints/detail.js.map +1 -0
  15. package/dist/server/broker/kiwoom/endpoints/investor.js +139 -0
  16. package/dist/server/broker/kiwoom/endpoints/investor.js.map +1 -0
  17. package/dist/server/broker/kiwoom/endpoints/order.js +134 -0
  18. package/dist/server/broker/kiwoom/endpoints/order.js.map +1 -0
  19. package/dist/server/broker/kiwoom/endpoints/quote.js +165 -0
  20. package/dist/server/broker/kiwoom/endpoints/quote.js.map +1 -0
  21. package/dist/server/broker/kiwoom/endpoints/ranking.js +180 -0
  22. package/dist/server/broker/kiwoom/endpoints/ranking.js.map +1 -0
  23. package/dist/server/broker/kiwoom/endpoints/sector.js +135 -0
  24. package/dist/server/broker/kiwoom/endpoints/sector.js.map +1 -0
  25. package/dist/server/broker/kiwoom/endpoints/theme.js +104 -0
  26. package/dist/server/broker/kiwoom/endpoints/theme.js.map +1 -0
  27. package/dist/server/broker/kiwoom/endpoints/universe.js +119 -0
  28. package/dist/server/broker/kiwoom/endpoints/universe.js.map +1 -0
  29. package/dist/server/broker/kiwoom/index.js +59 -0
  30. package/dist/server/broker/kiwoom/index.js.map +1 -0
  31. package/dist/server/broker/kiwoom/order-tracker.js +353 -0
  32. package/dist/server/broker/kiwoom/order-tracker.js.map +1 -0
  33. package/dist/server/broker/kiwoom/price-feed.js +119 -0
  34. package/dist/server/broker/kiwoom/price-feed.js.map +1 -0
  35. package/dist/server/broker/kiwoom/rate-limiter.js +97 -0
  36. package/dist/server/broker/kiwoom/rate-limiter.js.map +1 -0
  37. package/dist/server/broker/kiwoom/types.js +13 -0
  38. package/dist/server/broker/kiwoom/types.js.map +1 -0
  39. package/dist/server/broker/kiwoom/ws/client.js +370 -0
  40. package/dist/server/broker/kiwoom/ws/client.js.map +1 -0
  41. package/dist/server/broker/kiwoom/ws/endpoints/condition.js +146 -0
  42. package/dist/server/broker/kiwoom/ws/endpoints/condition.js.map +1 -0
  43. package/dist/server/broker/kiwoom/ws/realtime-bus.js +42 -0
  44. package/dist/server/broker/kiwoom/ws/realtime-bus.js.map +1 -0
  45. package/dist/server/broker/kiwoom/ws/types.js +19 -0
  46. package/dist/server/broker/kiwoom/ws/types.js.map +1 -0
  47. package/dist/server/broker/news.js +34 -0
  48. package/dist/server/broker/news.js.map +1 -0
  49. package/dist/server/bundle.js +43 -0
  50. package/dist/server/bundle.js.map +1 -0
  51. package/dist/server/calendar/krx-holidays.js +162 -0
  52. package/dist/server/calendar/krx-holidays.js.map +1 -0
  53. package/dist/server/config.js +263 -0
  54. package/dist/server/config.js.map +1 -0
  55. package/dist/server/db/sqlite.js +252 -0
  56. package/dist/server/db/sqlite.js.map +1 -0
  57. package/dist/server/diary/writer.js +266 -0
  58. package/dist/server/diary/writer.js.map +1 -0
  59. package/dist/server/index.js +316 -0
  60. package/dist/server/index.js.map +1 -0
  61. package/dist/server/jobs/universe-sync.js +132 -0
  62. package/dist/server/jobs/universe-sync.js.map +1 -0
  63. package/dist/server/jobs/watchdog.js +87 -0
  64. package/dist/server/jobs/watchdog.js.map +1 -0
  65. package/dist/server/journal/pnl-stats.js +108 -0
  66. package/dist/server/journal/pnl-stats.js.map +1 -0
  67. package/dist/server/journal/telemetry.js +174 -0
  68. package/dist/server/journal/telemetry.js.map +1 -0
  69. package/dist/server/journal/trade-journal.js +239 -0
  70. package/dist/server/journal/trade-journal.js.map +1 -0
  71. package/dist/server/llm/anthropic.js +98 -0
  72. package/dist/server/llm/anthropic.js.map +1 -0
  73. package/dist/server/llm/claude-cli.js +204 -0
  74. package/dist/server/llm/claude-cli.js.map +1 -0
  75. package/dist/server/llm/context-builder.js +229 -0
  76. package/dist/server/llm/context-builder.js.map +1 -0
  77. package/dist/server/llm/gemini.js +86 -0
  78. package/dist/server/llm/gemini.js.map +1 -0
  79. package/dist/server/llm/index.js +36 -0
  80. package/dist/server/llm/index.js.map +1 -0
  81. package/dist/server/llm/openai.js +87 -0
  82. package/dist/server/llm/openai.js.map +1 -0
  83. package/dist/server/personas/executor.js +318 -0
  84. package/dist/server/personas/executor.js.map +1 -0
  85. package/dist/server/personas/loader.js +165 -0
  86. package/dist/server/personas/loader.js.map +1 -0
  87. package/dist/server/personas/persona-agent.js +386 -0
  88. package/dist/server/personas/persona-agent.js.map +1 -0
  89. package/dist/server/personas/persona-state.js +170 -0
  90. package/dist/server/personas/persona-state.js.map +1 -0
  91. package/dist/server/personas/runner.js +162 -0
  92. package/dist/server/personas/runner.js.map +1 -0
  93. package/dist/server/personas/schema.js +123 -0
  94. package/dist/server/personas/schema.js.map +1 -0
  95. package/dist/server/personas/wake-plan.js +313 -0
  96. package/dist/server/personas/wake-plan.js.map +1 -0
  97. package/dist/server/readiness.js +414 -0
  98. package/dist/server/readiness.js.map +1 -0
  99. package/dist/server/routes.js +1216 -0
  100. package/dist/server/routes.js.map +1 -0
  101. package/dist/server/safety.js +153 -0
  102. package/dist/server/safety.js.map +1 -0
  103. package/dist/server/screener/engine.js +856 -0
  104. package/dist/server/screener/engine.js.map +1 -0
  105. package/dist/server/server-sync.js +427 -0
  106. package/dist/server/server-sync.js.map +1 -0
  107. package/dist/server/signing.js +39 -0
  108. package/dist/server/signing.js.map +1 -0
  109. package/dist/server/watchers/condition-watcher.js +519 -0
  110. package/dist/server/watchers/condition-watcher.js.map +1 -0
  111. package/dist/server/watchers/types.js +16 -0
  112. package/dist/server/watchers/types.js.map +1 -0
  113. package/dist/web/assets/index-62SMpbaf.js +79 -0
  114. package/dist/web/assets/index-BPLQR0wt.css +1 -0
  115. package/dist/web/index.html +14 -0
  116. package/package.json +93 -0
  117. package/scripts/com.mulsok.traders.client.plist.template +58 -0
  118. package/scripts/install-daemon.sh +156 -0
  119. package/scripts/uninstall-daemon.sh +62 -0
@@ -0,0 +1,519 @@
1
+ /**
2
+ * ConditionWatcher (apps/client)
3
+ *
4
+ * LLM 응답 wake_plan.watchers[] 를 받아 조건 등록 → 트리거 시 콜백 호출.
5
+ *
6
+ * 4 조건 유형 (types.ts ConditionType):
7
+ * - price · PriceFeed 구독 + 비교 평가
8
+ * - event · 분봉/일봉 패턴 (간소화 구현 · ma_touch / previous_low_break / candle_volume_surge 만)
9
+ * - time · setTimeout (절대 시각 또는 상대 ms)
10
+ * - composite · 자식들 AND/OR 평가 (자식 트리거 추적)
11
+ *
12
+ * 트리거 콜백
13
+ * - registry 에서 등록된 글로벌 onTrigger 호출 (executor 미구현 단계 · 일단 로그만)
14
+ * - watcher.spec.repeat === true 면 재무장 · 아니면 정리
15
+ *
16
+ * 만료 정책
17
+ * - max_wait_hours 초과 시 expired · 자동 unsubscribe
18
+ * - 분 단위 sweeper 가 만료 정리
19
+ */
20
+ import { randomUUID } from "node:crypto";
21
+ import { getPriceFeed } from "../broker/kiwoom/price-feed.js";
22
+ import { getDailyChart, getMinuteChart } from "../broker/kiwoom/index.js";
23
+ class ConditionWatcher {
24
+ watchers = new Map();
25
+ /** time 조건 timer 매핑 */
26
+ timeTimers = new Map();
27
+ /** 글로벌 트리거 콜백 (executor 가 등록 · 미등록 시 로그만) */
28
+ globalOnTrigger = null;
29
+ /** 만료 정리 sweeper */
30
+ sweepTimer = null;
31
+ start() {
32
+ if (this.sweepTimer)
33
+ return;
34
+ this.sweepTimer = setInterval(() => this.sweepExpired(), 60_000);
35
+ console.log("[ConditionWatcher] started · sweeper 60s");
36
+ }
37
+ stop() {
38
+ if (this.sweepTimer)
39
+ clearInterval(this.sweepTimer);
40
+ this.sweepTimer = null;
41
+ for (const id of Array.from(this.watchers.keys())) {
42
+ this.remove(id);
43
+ }
44
+ console.log("[ConditionWatcher] stopped · all watchers removed");
45
+ }
46
+ /**
47
+ * Graceful shutdown 전용: 메모리 timer 만 정리 + SQLite watchers 테이블 보존.
48
+ *
49
+ * `stop()` 과의 차이:
50
+ * - `stop()`: 모든 watcher revoked (SQLite 삭제) → 다시 시작 시 빈 상태
51
+ * - `pauseTimers()`: 메모리 timer/PriceFeed unsubscribe 만 정리 + DB 보존
52
+ * → SIGINT/SIGTERM 시 호출 → restart 후 `restoreFromDb()` 로 그대로 복원
53
+ *
54
+ * 자율 사이클 끊김 없도록 graceful (SPEC-25 line 743-744 보강).
55
+ */
56
+ pauseTimers() {
57
+ if (this.sweepTimer) {
58
+ clearInterval(this.sweepTimer);
59
+ this.sweepTimer = null;
60
+ }
61
+ let paused = 0;
62
+ for (const w of Array.from(this.watchers.values())) {
63
+ if (w.status === "active") {
64
+ this.stopWatching(w);
65
+ paused++;
66
+ }
67
+ }
68
+ console.log(`[ConditionWatcher] paused · ${paused} active timer cleared · DB preserved for restart`);
69
+ }
70
+ setGlobalTriggerCallback(cb) {
71
+ this.globalOnTrigger = cb;
72
+ }
73
+ /**
74
+ * 새 watcher 등록 · spec 1 개당 watcher 1 개
75
+ *
76
+ * @throws 미구현 type/metric 등록 시도 시 silent fail 방지를 위해 throw
77
+ * - composite type · P3 후속 본격 evaluator 도입 후 활성
78
+ * - price metric 'volume_ratio_d1' · 일봉 evaluator 별도 필요 (현재 0 반환 = 무한 트리거 위험)
79
+ */
80
+ add(personaSlug, spec) {
81
+ this.assertSupported(spec);
82
+ const id = `wt_${randomUUID().slice(0, 8)}`;
83
+ const now = new Date();
84
+ const expiresAt = new Date(now.getTime() + spec.maxWaitHours * 3600_000);
85
+ const watcher = {
86
+ id,
87
+ spec,
88
+ personaSlug,
89
+ createdAt: now.toISOString(),
90
+ expiresAt: expiresAt.toISOString(),
91
+ status: "active",
92
+ triggerCount: 0,
93
+ };
94
+ this.watchers.set(id, watcher);
95
+ this.persistWatcher(watcher);
96
+ this.startWatching(watcher);
97
+ console.log(`[ConditionWatcher] add ${id} · ${personaSlug} · ${spec.condition.type} · ${spec.intent}`);
98
+ return watcher;
99
+ }
100
+ /** 등록 해제 (active → revoked) */
101
+ remove(id, status = "revoked") {
102
+ const w = this.watchers.get(id);
103
+ if (!w)
104
+ return false;
105
+ this.stopWatching(w);
106
+ w.status = status;
107
+ if (status === "revoked" || status === "expired") {
108
+ this.watchers.delete(id);
109
+ this.persistDelete(id);
110
+ }
111
+ else {
112
+ // triggered — keep DB row for diagnostics + status update
113
+ this.persistWatcher(w);
114
+ }
115
+ return true;
116
+ }
117
+ /* ─────────── SQLite persistence (SPEC-11) ─────────── */
118
+ persistWatcher(w) {
119
+ try {
120
+ void import("../db/sqlite.js").then(({ upsertWatcher }) => {
121
+ upsertWatcher({
122
+ id: w.id,
123
+ persona_slug: w.personaSlug,
124
+ spec_json: JSON.stringify(w.spec),
125
+ created_at: w.createdAt,
126
+ expires_at: w.expiresAt,
127
+ trigger_count: w.triggerCount,
128
+ status: w.status,
129
+ });
130
+ });
131
+ }
132
+ catch (e) {
133
+ console.error("[ConditionWatcher] persist 실패:", e);
134
+ }
135
+ }
136
+ persistDelete(id) {
137
+ try {
138
+ void import("../db/sqlite.js").then(({ deleteWatcher }) => deleteWatcher(id));
139
+ }
140
+ catch (e) {
141
+ console.error("[ConditionWatcher] persistDelete 실패:", e);
142
+ }
143
+ }
144
+ /**
145
+ * Boot 시 active watcher SQLite 에서 복원.
146
+ * start() 다음에 호출해야 sweepTimer 가 만료 정리.
147
+ */
148
+ async restoreFromDb() {
149
+ try {
150
+ const { listActiveWatchers } = await import("../db/sqlite.js");
151
+ const rows = listActiveWatchers();
152
+ let restored = 0;
153
+ for (const r of rows) {
154
+ try {
155
+ const spec = JSON.parse(r.spec_json);
156
+ const w = {
157
+ id: r.id,
158
+ spec,
159
+ personaSlug: r.persona_slug,
160
+ createdAt: r.created_at,
161
+ expiresAt: r.expires_at,
162
+ status: "active",
163
+ triggerCount: r.trigger_count,
164
+ };
165
+ // 이미 만료된 watcher 는 skip + DB 정리
166
+ if (new Date(w.expiresAt).getTime() < Date.now()) {
167
+ this.persistDelete(w.id);
168
+ continue;
169
+ }
170
+ this.watchers.set(w.id, w);
171
+ this.startWatching(w);
172
+ restored++;
173
+ }
174
+ catch (e) {
175
+ console.warn(`[ConditionWatcher] restore 실패 · id=${r.id}:`, e);
176
+ this.persistDelete(r.id);
177
+ }
178
+ }
179
+ if (restored > 0)
180
+ console.log(`[ConditionWatcher] ${restored} watchers restored from DB`);
181
+ return restored;
182
+ }
183
+ catch (e) {
184
+ console.error("[ConditionWatcher] restoreFromDb 실패:", e);
185
+ return 0;
186
+ }
187
+ }
188
+ /** 활성 watcher 목록 */
189
+ list(opts = {}) {
190
+ return Array.from(this.watchers.values()).filter((w) => {
191
+ if (opts.personaSlug && w.personaSlug !== opts.personaSlug)
192
+ return false;
193
+ if (opts.activeOnly && w.status !== "active")
194
+ return false;
195
+ return true;
196
+ });
197
+ }
198
+ get(id) {
199
+ return this.watchers.get(id);
200
+ }
201
+ stats() {
202
+ let active = 0;
203
+ const byPersona = {};
204
+ for (const w of this.watchers.values()) {
205
+ if (w.status === "active")
206
+ active++;
207
+ byPersona[w.personaSlug] = (byPersona[w.personaSlug] ?? 0) + 1;
208
+ }
209
+ return { total: this.watchers.size, active, byPersona };
210
+ }
211
+ /**
212
+ * 미구현 type/metric 거부 · silent fail 방지
213
+ * 사용자가 등록했는데 영원히 trigger 안 되는 상황을 막음.
214
+ */
215
+ assertSupported(spec) {
216
+ const c = spec.condition;
217
+ if (c.type === "composite") {
218
+ throw new Error("[ConditionWatcher] composite type 은 P3 후속 evaluator 도입 후 지원 · 현재 미구현");
219
+ }
220
+ if (c.type === "price" && c.config.metric === "volume_ratio_d1") {
221
+ throw new Error("[ConditionWatcher] price.metric 'volume_ratio_d1' 은 일봉 evaluator 별도 필요 · 현재 미구현 (0 반환으로 무한 트리거 위험)");
222
+ }
223
+ }
224
+ /* ─────────── 내부 · 조건별 시작/종료 ─────────── */
225
+ startWatching(w) {
226
+ const c = w.spec.condition;
227
+ switch (c.type) {
228
+ case "price":
229
+ return this.startPrice(w, c.config);
230
+ case "event":
231
+ return this.startEvent(w, c.config);
232
+ case "time":
233
+ return this.startTime(w, c.config);
234
+ case "composite":
235
+ // 자식들을 등록 (각자 트리거 시 부모 평가)
236
+ // 구현 단순화: 첫 트리거 시 부모도 트리거 (or) · 모두 트리거 시 부모 트리거 (and)
237
+ return this.startComposite(w, c);
238
+ }
239
+ }
240
+ stopWatching(w) {
241
+ const c = w.spec.condition;
242
+ if (c.type === "price") {
243
+ getPriceFeed().unsubscribe(c.config.symbolCode, w.id);
244
+ }
245
+ else if (c.type === "time") {
246
+ const t = this.timeTimers.get(w.id);
247
+ if (t)
248
+ clearTimeout(t);
249
+ this.timeTimers.delete(w.id);
250
+ }
251
+ else if (c.type === "event") {
252
+ // event 는 PriceFeed 구독 + 추가 chart fetch · subscribe 만 정리
253
+ getPriceFeed().unsubscribe(c.config.symbolCode, w.id);
254
+ }
255
+ else if (c.type === "composite") {
256
+ // 자식들 정리 · composite 는 별도 추적 없음 (자식이 자기 watcher 로 등록)
257
+ }
258
+ }
259
+ /* ─────────── price 조건 ─────────── */
260
+ startPrice(w, cfg) {
261
+ const intervalMs = cfg.checkIntervalMs ?? 30_000;
262
+ getPriceFeed().subscribe(cfg.symbolCode, w.id, intervalMs, async (data) => {
263
+ const value = this.computePriceMetric(cfg, data);
264
+ const triggered = compareValue(value, cfg.op, cfg.value);
265
+ w.lastEvaluatedAt = new Date().toISOString();
266
+ w.lastEvaluationMeta = { metric: cfg.metric, value, threshold: cfg.value, op: cfg.op };
267
+ if (triggered && w.status === "active") {
268
+ await this.handleTrigger(w, { lastPrice: data, ...w.lastEvaluationMeta });
269
+ }
270
+ });
271
+ }
272
+ computePriceMetric(cfg, data) {
273
+ switch (cfg.metric) {
274
+ case "current_price":
275
+ return data.currentPriceKrw;
276
+ case "change_pct":
277
+ return data.changePct;
278
+ case "from_open_pct":
279
+ if (data.openKrw <= 0)
280
+ return 0;
281
+ return ((data.currentPriceKrw - data.openKrw) / data.openKrw) * 100;
282
+ case "from_buy_price_pct":
283
+ if (!cfg.buyPriceKrw || cfg.buyPriceKrw <= 0)
284
+ return 0;
285
+ return ((data.currentPriceKrw - cfg.buyPriceKrw) / cfg.buyPriceKrw) * 100;
286
+ case "volume_ratio_d1":
287
+ // 캐시된 일봉이 필요 · 단순 구현으로 0 반환 (별도 evaluator 권장)
288
+ return 0;
289
+ }
290
+ }
291
+ /* ─────────── event 조건 (간소화) ─────────── */
292
+ startEvent(w, cfg) {
293
+ // event 는 분봉/일봉 fetch 필요 · 30s 주기 PriceFeed 구독으로 trigger
294
+ const intervalMs = cfg.checkIntervalMs ?? 60_000;
295
+ getPriceFeed().subscribe(cfg.symbolCode, w.id, intervalMs, async (priceData) => {
296
+ let triggered = false;
297
+ let meta = { current: priceData.currentPriceKrw };
298
+ try {
299
+ switch (cfg.metric) {
300
+ case "ma_touch":
301
+ case "ma_break_below":
302
+ case "ma_break_above": {
303
+ const period = cfg.maPeriod ?? 5;
304
+ const ma = await this.computeMA(cfg.symbolCode, period);
305
+ if (ma === null)
306
+ break;
307
+ meta = { ...meta, ma, period };
308
+ const px = priceData.currentPriceKrw;
309
+ if (cfg.metric === "ma_touch") {
310
+ triggered = Math.abs(px - ma) / ma <= 0.005; // ±0.5%
311
+ }
312
+ else if (cfg.metric === "ma_break_below") {
313
+ triggered = px < ma;
314
+ }
315
+ else {
316
+ triggered = px > ma;
317
+ }
318
+ break;
319
+ }
320
+ case "previous_low_break": {
321
+ const candles = await this.fetchDailyCandles(cfg.symbolCode, 2);
322
+ if (candles.length < 2)
323
+ break;
324
+ const prevLow = candles[1].lowKrw;
325
+ const prevAvgVol = candles[1].volume;
326
+ meta = { ...meta, prevLow, prevAvgVol };
327
+ triggered =
328
+ priceData.currentPriceKrw < prevLow && priceData.volume > prevAvgVol * 0.5;
329
+ break;
330
+ }
331
+ case "candle_volume_surge": {
332
+ const mult = cfg.volumeMultiple ?? 2;
333
+ const candles = await this.fetchDailyCandles(cfg.symbolCode, 2);
334
+ if (candles.length < 2)
335
+ break;
336
+ const prevVol = candles[1].volume;
337
+ meta = { ...meta, prevVol, mult };
338
+ triggered = priceData.volume >= prevVol * mult;
339
+ break;
340
+ }
341
+ case "bullish_engulfing":
342
+ case "high_volume_bearish": {
343
+ // 분봉 패턴 평가 (간소 · 분봉 5분 5개)
344
+ const candles = await this.fetchMinuteCandles(cfg.symbolCode, 5, 5);
345
+ if (candles.length < 2)
346
+ break;
347
+ const last = candles[0];
348
+ const prev = candles[1];
349
+ if (cfg.metric === "bullish_engulfing") {
350
+ triggered =
351
+ last.closeKrw > last.openKrw &&
352
+ prev.closeKrw < prev.openKrw &&
353
+ last.closeKrw >= prev.openKrw &&
354
+ last.openKrw <= prev.closeKrw;
355
+ }
356
+ else {
357
+ const avgVol = candles.slice(1).reduce((s, c) => s + c.volume, 0) / Math.max(1, candles.length - 1);
358
+ triggered =
359
+ last.closeKrw < last.openKrw && last.volume > avgVol * 1.5;
360
+ }
361
+ meta = { ...meta, last, prev };
362
+ break;
363
+ }
364
+ }
365
+ }
366
+ catch (e) {
367
+ console.error(`[ConditionWatcher] ${w.id} event eval err:`, e);
368
+ }
369
+ w.lastEvaluatedAt = new Date().toISOString();
370
+ w.lastEvaluationMeta = { metric: cfg.metric, ...meta };
371
+ if (triggered && w.status === "active") {
372
+ await this.handleTrigger(w, w.lastEvaluationMeta);
373
+ }
374
+ });
375
+ }
376
+ async computeMA(symbolCode, period) {
377
+ const candles = await this.fetchDailyCandles(symbolCode, period);
378
+ if (candles.length < period)
379
+ return null;
380
+ const sum = candles.slice(0, period).reduce((s, c) => s + c.closeKrw, 0);
381
+ return sum / period;
382
+ }
383
+ async fetchDailyCandles(symbolCode, days) {
384
+ const res = await getDailyChart(symbolCode, Math.max(days, 5));
385
+ if (!res.ok)
386
+ return [];
387
+ return res.data.candles;
388
+ }
389
+ async fetchMinuteCandles(symbolCode, intervalMin, count) {
390
+ const res = await getMinuteChart(symbolCode, intervalMin, count);
391
+ if (!res.ok)
392
+ return [];
393
+ return res.data.candles;
394
+ }
395
+ /* ─────────── time 조건 ─────────── */
396
+ //
397
+ // restart resilience (SPEC-11):
398
+ // - 발화 시각은 절대 시점 기준 (createdAt + afterMs 또는 at)
399
+ // - server restart 시 startTime 이 다시 호출되면 남은 delay 만 setTimeout
400
+ // - 이미 발화 시점 지났으면 delayMs=0 → 즉시 발화 (만료 X 인 경우)
401
+ // - 만료된 watcher 는 restoreFromDb 가 아예 skip (SQLite expires_at 검증)
402
+ startTime(w, cfg) {
403
+ let firesAtMs;
404
+ if (cfg.at) {
405
+ firesAtMs = new Date(cfg.at).getTime();
406
+ }
407
+ else if (cfg.afterMs) {
408
+ // afterMs 는 createdAt 기준 — restart 시에도 같은 절대 시각에 발화
409
+ firesAtMs = new Date(w.createdAt).getTime() + cfg.afterMs;
410
+ }
411
+ else {
412
+ // 둘 다 없으면 즉시 (방어 · spec 단계에서 보통 차단됨)
413
+ firesAtMs = Date.now();
414
+ }
415
+ // defense-in-depth: ISO 가 아닌 KST 마커가 그대로 도달하면 NaN.
416
+ // setTimeout(NaN) 은 0 으로 coerce 되어 즉시 발화 → invalid 마크 + 로그.
417
+ if (Number.isNaN(firesAtMs)) {
418
+ console.error(`[ConditionWatcher] ${w.id} time.at 파싱 실패 ("${cfg.at}") · 즉시 발화 차단 + 만료 처리`);
419
+ w.status = "expired";
420
+ this.persistWatcher(w);
421
+ return;
422
+ }
423
+ const delayMs = Math.max(0, firesAtMs - Date.now());
424
+ const t = setTimeout(() => {
425
+ void this.handleTrigger(w, { firedAt: new Date().toISOString() });
426
+ }, delayMs);
427
+ this.timeTimers.set(w.id, t);
428
+ }
429
+ /* ─────────── composite 조건 (단순) ─────────── */
430
+ startComposite(w, c) {
431
+ // 단순화: composite 는 자식 spec 들을 별개 watcher 로 등록하지 않고
432
+ // 부모만 active 유지 + 자식 평가는 inline (P3 MVP).
433
+ // 본격 구현은 별도 evaluator 클래스 필요.
434
+ void c;
435
+ console.warn(`[ConditionWatcher] ${w.id} composite type · MVP 구현 미완 (인라인 평가 필요)`);
436
+ }
437
+ /* ─────────── 트리거 처리 ─────────── */
438
+ async handleTrigger(w, triggerData) {
439
+ if (w.status !== "active")
440
+ return;
441
+ w.triggerCount += 1;
442
+ w.triggeredAt = new Date().toISOString();
443
+ const ctx = {
444
+ watcher: { ...w },
445
+ triggeredAt: w.triggeredAt,
446
+ triggerData,
447
+ };
448
+ console.log(`[ConditionWatcher] TRIGGERED ${w.id} · ${w.personaSlug} · ${w.spec.intent} · count=${w.triggerCount}`);
449
+ // executor 콜백 호출 (없으면 로그만)
450
+ if (this.globalOnTrigger) {
451
+ try {
452
+ await this.globalOnTrigger(ctx);
453
+ }
454
+ catch (e) {
455
+ console.error(`[ConditionWatcher] trigger callback err:`, e);
456
+ }
457
+ }
458
+ // repeat false → 정리
459
+ if (!w.spec.repeat) {
460
+ this.remove(w.id, "triggered");
461
+ }
462
+ else {
463
+ // repeat 인 경우는 status active 유지 · 다음 평가 시 다시 trigger 가능
464
+ w.status = "active";
465
+ }
466
+ }
467
+ /* ─────────── 만료 정리 ─────────── */
468
+ sweepExpired() {
469
+ const now = Date.now();
470
+ let removed = 0;
471
+ for (const w of Array.from(this.watchers.values())) {
472
+ if (w.status !== "active")
473
+ continue;
474
+ if (new Date(w.expiresAt).getTime() <= now) {
475
+ // P2-5: 만료도 trade-journal 에 기록 (사후 "watcher 가 왜 사라졌나?" 답)
476
+ // SPEC-9 enum 5종 안에서 watcher_triggered eventType 활용 + lifecycle 메타로 구분.
477
+ // dynamic import 로 순환 의존 회피 (trade-journal → telemetry → ... 순환 위험).
478
+ const expiredWatcher = w; // closure capture
479
+ void import("../journal/trade-journal.js").then(({ logWatcherTriggered }) => {
480
+ logWatcherTriggered({
481
+ personaSlug: expiredWatcher.personaSlug,
482
+ watcherId: expiredWatcher.id,
483
+ intent: expiredWatcher.spec.intent,
484
+ triggerData: {
485
+ lifecycle: "expired",
486
+ expiresAt: expiredWatcher.expiresAt,
487
+ triggerCount: expiredWatcher.triggerCount,
488
+ maxWaitHours: expiredWatcher.spec.maxWaitHours,
489
+ conditionType: expiredWatcher.spec.condition.type,
490
+ },
491
+ });
492
+ }).catch((e) => {
493
+ console.error(`[ConditionWatcher] expired journal 기록 실패 · ${expiredWatcher.id}:`, e);
494
+ });
495
+ this.remove(w.id, "expired");
496
+ removed++;
497
+ }
498
+ }
499
+ if (removed > 0) {
500
+ console.log(`[ConditionWatcher] sweep · ${removed} expired watchers removed`);
501
+ }
502
+ }
503
+ }
504
+ function compareValue(value, op, threshold) {
505
+ switch (op) {
506
+ case "gte": return value >= threshold;
507
+ case "gt": return value > threshold;
508
+ case "lte": return value <= threshold;
509
+ case "lt": return value < threshold;
510
+ case "eq": return value === threshold;
511
+ }
512
+ }
513
+ let singleton = null;
514
+ export function getConditionWatcher() {
515
+ if (!singleton)
516
+ singleton = new ConditionWatcher();
517
+ return singleton;
518
+ }
519
+ //# sourceMappingURL=condition-watcher.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"condition-watcher.js","sourceRoot":"","sources":["../../../src-server/watchers/condition-watcher.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Watcher 시스템 타입 (apps/client)
3
+ *
4
+ * 흐름:
5
+ * 1. LLM 응답 wake_plan.watchers[] 수신
6
+ * 2. ConditionWatcher.add(spec) 호출 → 조건 등록
7
+ * 3. PriceFeed (price 타입) 또는 setTimeout (time 타입) 또는 직접 평가 (event/composite)
8
+ * 가 조건 모니터링
9
+ * 4. 트리거 발생 → onTrigger 콜백 (보통 LLM 재호출 큐 push)
10
+ * 5. condition.status = "triggered" → 자동 정리 또는 재무장 (재무장 정책은 spec.repeat)
11
+ *
12
+ * 단일 프로세스 인메모리 (단일 Fastify 인스턴스 가정).
13
+ * 향후 SQLite 영구화 가능 (executor 재시작 후에도 watchers 복원).
14
+ */
15
+ export {};
16
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src-server/watchers/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG"}