koishi-plugin-monetary-bourse 1.1.2-Alpha.6 → 1.1.2-Alpha.7
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.
- package/lib/index.js +41 -17
- package/package.json +1 -1
- package/readme.md +30 -14
package/lib/index.js
CHANGED
|
@@ -377,21 +377,18 @@ function apply(ctx, config) {
|
|
|
377
377
|
}
|
|
378
378
|
const createAutoState = /* @__PURE__ */ __name(async () => {
|
|
379
379
|
const durationHours = 7 * 24;
|
|
380
|
-
const fluctuation = 0.
|
|
380
|
+
const fluctuation = 0.25;
|
|
381
381
|
const targetRatio = 1 + (Math.random() * 2 - 1) * fluctuation;
|
|
382
|
-
let
|
|
383
|
-
|
|
384
|
-
const lowerTarget = currentPrice * 0.5;
|
|
385
|
-
targetPrice = Math.max(lowerTarget, Math.min(upperTarget, targetPrice));
|
|
382
|
+
let targetPrice2 = currentPrice * targetRatio;
|
|
383
|
+
targetPrice2 = Math.max(currentPrice * 0.5, Math.min(currentPrice * 1.5, targetPrice2));
|
|
386
384
|
const endTime = new Date(now.getTime() + durationHours * 3600 * 1e3);
|
|
387
|
-
const minutes = durationHours * 60;
|
|
388
|
-
const trendFactor = (targetPrice - currentPrice) / minutes;
|
|
389
385
|
const newState = {
|
|
390
386
|
key: "macro_state",
|
|
391
387
|
lastCycleStart: now,
|
|
392
388
|
startPrice: currentPrice,
|
|
393
|
-
targetPrice,
|
|
394
|
-
trendFactor,
|
|
389
|
+
targetPrice: targetPrice2,
|
|
390
|
+
trendFactor: 0,
|
|
391
|
+
// 不再使用线性趋势因子
|
|
395
392
|
mode: "auto",
|
|
396
393
|
endTime
|
|
397
394
|
};
|
|
@@ -415,10 +412,10 @@ function apply(ctx, config) {
|
|
|
415
412
|
switchKLinePattern("随机时间");
|
|
416
413
|
}
|
|
417
414
|
const basePrice = state.startPrice;
|
|
415
|
+
const targetPrice = state.targetPrice;
|
|
418
416
|
const totalDuration = state.endTime.getTime() - state.lastCycleStart.getTime();
|
|
419
|
-
const elapsed =
|
|
417
|
+
const elapsed = now.getTime() - state.lastCycleStart.getTime();
|
|
420
418
|
const cycleProgress = Math.max(0, Math.min(1, elapsed / totalDuration));
|
|
421
|
-
const trendPrice = basePrice + (state.targetPrice - basePrice) * cycleProgress;
|
|
422
419
|
const dayStart = new Date(now);
|
|
423
420
|
dayStart.setHours(config.openHour, 0, 0, 0);
|
|
424
421
|
const dayEnd = new Date(now);
|
|
@@ -426,13 +423,32 @@ function apply(ctx, config) {
|
|
|
426
423
|
const dayDuration = dayEnd.getTime() - dayStart.getTime();
|
|
427
424
|
const dayElapsed = now.getTime() - dayStart.getTime();
|
|
428
425
|
const dayProgress = Math.max(0, Math.min(1, dayElapsed / dayDuration));
|
|
426
|
+
const expectedPrice = basePrice + (targetPrice - basePrice) * cycleProgress;
|
|
427
|
+
const deviation = (expectedPrice - currentPrice) / currentPrice;
|
|
428
|
+
const meanReversionStrength = 0.02;
|
|
429
|
+
const driftReturn = deviation * meanReversionStrength;
|
|
430
|
+
const getVolatility = /* @__PURE__ */ __name((progress) => {
|
|
431
|
+
const morningVol = Math.exp(-8 * progress);
|
|
432
|
+
const afternoonVol = Math.exp(-8 * (1 - progress));
|
|
433
|
+
const baseVol = 0.3;
|
|
434
|
+
return baseVol + morningVol * 0.5 + afternoonVol * 0.4;
|
|
435
|
+
}, "getVolatility");
|
|
436
|
+
const volatility = getVolatility(dayProgress);
|
|
437
|
+
const u1 = Math.random();
|
|
438
|
+
const u2 = Math.random();
|
|
439
|
+
const normalRandom = Math.sqrt(-2 * Math.log(u1)) * Math.cos(2 * Math.PI * u2);
|
|
440
|
+
const baseVolatilityPerTick = 15e-4;
|
|
441
|
+
const randomReturn = normalRandom * baseVolatilityPerTick * volatility;
|
|
429
442
|
const patternFn = kLinePatterns[currentDayPattern];
|
|
430
|
-
const
|
|
431
|
-
const
|
|
432
|
-
const
|
|
433
|
-
const
|
|
434
|
-
const
|
|
435
|
-
|
|
443
|
+
const patternValue = patternFn(dayProgress);
|
|
444
|
+
const prevPatternValue = patternFn(Math.max(0, dayProgress - 0.01));
|
|
445
|
+
const patternTrend = (patternValue - prevPatternValue) * 0.5;
|
|
446
|
+
const patternBias = patternTrend * 3e-3;
|
|
447
|
+
const wavePhase = 2 * Math.PI * macroWaveCount * cycleProgress;
|
|
448
|
+
const prevWavePhase = 2 * Math.PI * macroWaveCount * Math.max(0, cycleProgress - 1e-3);
|
|
449
|
+
const waveTrend = (Math.sin(wavePhase) - Math.sin(prevWavePhase)) * macroWeeklyAmplitudeRatio;
|
|
450
|
+
const totalReturn = driftReturn + randomReturn + patternBias + waveTrend;
|
|
451
|
+
let newPrice = currentPrice * (1 + totalReturn);
|
|
436
452
|
const dayBase = dailyOpenPrice ?? basePrice;
|
|
437
453
|
const weekUpper = basePrice * 1.5;
|
|
438
454
|
const weekLower = basePrice * 0.5;
|
|
@@ -440,6 +456,14 @@ function apply(ctx, config) {
|
|
|
440
456
|
const dayLower = dayBase * 0.5;
|
|
441
457
|
const upperLimit = Math.min(weekUpper, dayUpper);
|
|
442
458
|
const lowerLimit = Math.max(weekLower, dayLower);
|
|
459
|
+
if (newPrice > upperLimit * 0.95) {
|
|
460
|
+
const overshoot = (newPrice - upperLimit * 0.95) / (upperLimit * 0.05);
|
|
461
|
+
newPrice = upperLimit * 0.95 + upperLimit * 0.05 * Math.tanh(overshoot);
|
|
462
|
+
}
|
|
463
|
+
if (newPrice < lowerLimit * 1.05) {
|
|
464
|
+
const undershoot = (lowerLimit * 1.05 - newPrice) / (lowerLimit * 0.05);
|
|
465
|
+
newPrice = lowerLimit * 1.05 - lowerLimit * 0.05 * Math.tanh(undershoot);
|
|
466
|
+
}
|
|
443
467
|
newPrice = Math.max(lowerLimit, Math.min(upperLimit, newPrice));
|
|
444
468
|
if (newPrice < 1) newPrice = 1;
|
|
445
469
|
newPrice = Number(newPrice.toFixed(2));
|
package/package.json
CHANGED
package/readme.md
CHANGED
|
@@ -19,8 +19,17 @@
|
|
|
19
19
|
|
|
20
20
|
## 更新记录
|
|
21
21
|
|
|
22
|
+
- **Alpha.7**:
|
|
23
|
+
- **采用真实股票模型**:使用几何布朗运动 + 均值回归模型,更贴近真实股票走势。
|
|
24
|
+
- 新增:均值回归机制——价格会自然向"预期价格"回归,而非硬性跳变。
|
|
25
|
+
- 新增:动态波动率——开盘和收盘波动大,午盘相对平静(U型波动率曲线)。
|
|
26
|
+
- 新增:正态分布随机项——使用Box-Muller变换生成更真实的随机波动。
|
|
27
|
+
- 新增:软着陆限幅——接近涨跌幅限制时逐渐减缓,避免硬切导致的不自然走势。
|
|
28
|
+
- 优化:K线形态改为提供方向性偏置,而非直接决定价格位置。
|
|
29
|
+
- 优化:周期波浪改为增量式叠加,更平滑自然。
|
|
30
|
+
|
|
22
31
|
- **Alpha.6**:
|
|
23
|
-
-
|
|
32
|
+
- **再次重构**:改用百分比波动模式,所有波动(K线、周波浪、噪音)以百分比形式叠加在趋势价格上,彻底解决振幅失控问题。
|
|
24
33
|
- 修复:手动宏观调控不再重置周期基准价和起点,保持现有波动机制持续生效。
|
|
25
34
|
- 优化:K线波动幅度调整为±3%,周波浪和噪音也改为百分比计算,波动更符合真实股票特性。
|
|
26
35
|
- 性能:新的百分比合成模式更稳定,长期运行不会出现价格失控或波动失效。
|
|
@@ -137,10 +146,6 @@
|
|
|
137
146
|
- 开发测试:推进价格更新若干次并返回当前价格。
|
|
138
147
|
- 参数 `ticks`: 推进次数,默认 1,最大 500。
|
|
139
148
|
|
|
140
|
-
- 【默认不开启】**`bourse.test.clamp <percent>`**
|
|
141
|
-
- 开发测试:尝试目标涨跌幅并查看限幅结果。
|
|
142
|
-
- 参数 `percent`: 期望涨跌百分比,例如 `60` 或 `-40`。
|
|
143
|
-
|
|
144
149
|
## 💡 常见问题
|
|
145
150
|
|
|
146
151
|
**Q:Alpha版本有什么区别?**
|
|
@@ -156,17 +161,28 @@ A: 本插件设计了基于交易金额的动态冻结机制。交易额越大
|
|
|
156
161
|
---
|
|
157
162
|
|
|
158
163
|
**Q: 股价是如何波动的?**
|
|
159
|
-
A:
|
|
164
|
+
A: 股价采用**几何布朗运动 + 均值回归**模型(Alpha.7),更贴近真实股票:
|
|
165
|
+
|
|
166
|
+
**核心公式:** `新价格 = 当前价格 × (1 + 总收益率)`
|
|
167
|
+
|
|
168
|
+
**总收益率由以下部分组成:**
|
|
169
|
+
|
|
170
|
+
1. **均值回归项(Drift)**:价格会自然向"预期价格"回归
|
|
171
|
+
- 预期价格 = 周期起始价 → 目标价的线性插值
|
|
172
|
+
- 偏离越大,回归力越强(每次回归2%的偏差)
|
|
160
173
|
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
4. **微小噪音**:±0.1%的随机扰动避免价格过于规律。
|
|
174
|
+
2. **随机波动项(Random Walk)**:模拟市场的随机性
|
|
175
|
+
- 使用正态分布随机数(Box-Muller变换)
|
|
176
|
+
- 基础波动率约0.15%/tick
|
|
165
177
|
|
|
166
|
-
|
|
178
|
+
3. **动态波动率**:模拟日内波动率变化
|
|
179
|
+
- 开盘:波动率高(活跃交易)
|
|
180
|
+
- 午盘:波动率低(相对平静)
|
|
181
|
+
- 尾盘:波动率再次升高
|
|
167
182
|
|
|
168
|
-
|
|
183
|
+
4. **K线形态偏置**:12种日内形态提供微小的方向性偏好
|
|
184
|
+
- 不再直接决定价格位置,而是影响涨跌概率
|
|
169
185
|
|
|
170
|
-
|
|
186
|
+
5. **周期波浪**:中期波动,模拟市场情绪周期
|
|
171
187
|
|
|
172
|
-
|
|
188
|
+
**限幅机制:** 相对于周期起始价和日开盘价的±50%,采用软着陆方式避免硬切。
|