koishi-plugin-monetary-bourse 3.0.0-alpha.18 → 3.0.0-alpha.19
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/commands-admin.d.ts +1 -0
- package/lib/index.d.ts +8 -0
- package/lib/index.js +84 -9
- package/package.json +1 -1
- package/readme.md +44 -2
package/lib/commands-admin.d.ts
CHANGED
|
@@ -9,6 +9,7 @@ type AdminCommandDeps = {
|
|
|
9
9
|
setWasMarketOpen: (value: boolean) => void;
|
|
10
10
|
isMarketOpen: () => Promise<boolean>;
|
|
11
11
|
switchKLinePattern: (reason: string, expectedPrice?: number, cycleProgress?: number) => void;
|
|
12
|
+
broadcastMacroNews: (targetPrice: number, basePrice: number) => Promise<void>;
|
|
12
13
|
};
|
|
13
14
|
export declare function registerAdminCommands(deps: AdminCommandDeps): void;
|
|
14
15
|
export {};
|
package/lib/index.d.ts
CHANGED
|
@@ -68,6 +68,10 @@ export type SellFeeTier = {
|
|
|
68
68
|
minAmount: number;
|
|
69
69
|
feePercent: number;
|
|
70
70
|
};
|
|
71
|
+
export type NewsItem = {
|
|
72
|
+
text: string;
|
|
73
|
+
weight: number;
|
|
74
|
+
};
|
|
71
75
|
export interface Config {
|
|
72
76
|
currency: string;
|
|
73
77
|
stockName: string;
|
|
@@ -87,6 +91,10 @@ export interface Config {
|
|
|
87
91
|
biasMax: number;
|
|
88
92
|
dividendIntervalDays: number;
|
|
89
93
|
maxDividendRate: number;
|
|
94
|
+
newsDeviationThreshold: number;
|
|
95
|
+
broadcastChannels: string[];
|
|
96
|
+
positiveNews: NewsItem[];
|
|
97
|
+
negativeNews: NewsItem[];
|
|
90
98
|
}
|
|
91
99
|
export declare const Config: Schema<Config>;
|
|
92
100
|
export declare function apply(ctx: Context, config: Config): void;
|
package/lib/index.js
CHANGED
|
@@ -522,7 +522,8 @@ function registerAdminCommands(deps) {
|
|
|
522
522
|
getDailyOpenPrice,
|
|
523
523
|
setWasMarketOpen,
|
|
524
524
|
isMarketOpen,
|
|
525
|
-
switchKLinePattern
|
|
525
|
+
switchKLinePattern,
|
|
526
|
+
broadcastMacroNews
|
|
526
527
|
} = deps;
|
|
527
528
|
ctx.command(
|
|
528
529
|
"stock.control <price:number> [hours:number]",
|
|
@@ -568,6 +569,7 @@ function registerAdminCommands(deps) {
|
|
|
568
569
|
updateFields
|
|
569
570
|
);
|
|
570
571
|
}
|
|
572
|
+
await broadcastMacroNews(targetPriceClamped, currentPrice);
|
|
571
573
|
const hint = targetPriceClamped !== price ? `(已按±50%限幅从${price}调整为${Number(targetPriceClamped.toFixed(2))})` : "";
|
|
572
574
|
return `宏观调控已设置:
|
|
573
575
|
目标价格:${Number(targetPriceClamped.toFixed(2))}${hint}
|
|
@@ -1292,6 +1294,44 @@ var Config = import_koishi2.Schema.intersect([
|
|
|
1292
1294
|
dividendIntervalDays: import_koishi2.Schema.number().min(1).step(1).default(7).description("分红结算周期(天)"),
|
|
1293
1295
|
maxDividendRate: import_koishi2.Schema.number().min(0).max(1).step(0.01).default(0.15).description("最大分红期望利润率(0-1,超出部分用于除息而非派发)")
|
|
1294
1296
|
}).description("分红机制"),
|
|
1297
|
+
import_koishi2.Schema.object({
|
|
1298
|
+
newsDeviationThreshold: import_koishi2.Schema.number().min(0.05).max(1).step(0.01).default(0.15).description(
|
|
1299
|
+
"触发新闻的偏离度阈值(例如 0.15 表示当新目标价与当前价相差 15% 以上时触发)"
|
|
1300
|
+
),
|
|
1301
|
+
broadcastChannels: import_koishi2.Schema.array(import_koishi2.Schema.string()).default([]).description(
|
|
1302
|
+
"播报新闻的频道/群聊 ID 列表(为空则只在后台输出日志,不发送群消息)"
|
|
1303
|
+
),
|
|
1304
|
+
positiveNews: import_koishi2.Schema.array(
|
|
1305
|
+
import_koishi2.Schema.object({
|
|
1306
|
+
text: import_koishi2.Schema.string().description("新闻文本"),
|
|
1307
|
+
weight: import_koishi2.Schema.number().min(1).step(1).default(1).description("权重")
|
|
1308
|
+
})
|
|
1309
|
+
).role("table").default([
|
|
1310
|
+
{
|
|
1311
|
+
text: "【财经快讯】{stockName} 宣布取得重大技术突破,预期利润大增!",
|
|
1312
|
+
weight: 1
|
|
1313
|
+
},
|
|
1314
|
+
{
|
|
1315
|
+
text: "【市场异动】神秘巨头入局,{stockName} 获大额资本注资!",
|
|
1316
|
+
weight: 1
|
|
1317
|
+
}
|
|
1318
|
+
]).description("利好新闻列表(可用 {stockName} 作为股票名称的占位符)"),
|
|
1319
|
+
negativeNews: import_koishi2.Schema.array(
|
|
1320
|
+
import_koishi2.Schema.object({
|
|
1321
|
+
text: import_koishi2.Schema.string().description("新闻文本"),
|
|
1322
|
+
weight: import_koishi2.Schema.number().min(1).step(1).default(1).description("权重")
|
|
1323
|
+
})
|
|
1324
|
+
).role("table").default([
|
|
1325
|
+
{
|
|
1326
|
+
text: "【黑天鹅】{stockName} 遭遇大规模不可抗力打击,市场恐慌情绪蔓延!",
|
|
1327
|
+
weight: 1
|
|
1328
|
+
},
|
|
1329
|
+
{
|
|
1330
|
+
text: "【行业悲报】{stockName} 最新季度财报严重不及预期,高管集体减持!",
|
|
1331
|
+
weight: 1
|
|
1332
|
+
}
|
|
1333
|
+
]).description("利空新闻列表(可用 {stockName} 作为股票名称的占位符)")
|
|
1334
|
+
}).description("新闻播报机制"),
|
|
1295
1335
|
import_koishi2.Schema.object({
|
|
1296
1336
|
enableDebug: import_koishi2.Schema.boolean().default(false).description("启用调试模式(开启后可使用调试指令)")
|
|
1297
1337
|
}).description("开发者选项")
|
|
@@ -1673,6 +1713,35 @@ function apply(ctx, config) {
|
|
|
1673
1713
|
return { success: true };
|
|
1674
1714
|
}
|
|
1675
1715
|
__name(pay, "pay");
|
|
1716
|
+
async function broadcastMacroNews(targetPrice, basePrice) {
|
|
1717
|
+
const deviation = (targetPrice - basePrice) / basePrice;
|
|
1718
|
+
if (Math.abs(deviation) < config.newsDeviationThreshold) return;
|
|
1719
|
+
const newsPool = deviation > 0 ? config.positiveNews : config.negativeNews;
|
|
1720
|
+
if (!newsPool || newsPool.length === 0) return;
|
|
1721
|
+
const totalWeight = newsPool.reduce((sum, item) => sum + item.weight, 0);
|
|
1722
|
+
if (totalWeight <= 0) return;
|
|
1723
|
+
let roll = Math.random() * totalWeight;
|
|
1724
|
+
let selected = newsPool[newsPool.length - 1];
|
|
1725
|
+
for (const item of newsPool) {
|
|
1726
|
+
roll -= item.weight;
|
|
1727
|
+
if (roll < 0) {
|
|
1728
|
+
selected = item;
|
|
1729
|
+
break;
|
|
1730
|
+
}
|
|
1731
|
+
}
|
|
1732
|
+
const newsText = selected.text.replace(/\{stockName\}/g, config.stockName);
|
|
1733
|
+
logger.info(
|
|
1734
|
+
`触发宏观新闻播报: ${newsText} (偏离度=${(deviation * 100).toFixed(2)}%)`
|
|
1735
|
+
);
|
|
1736
|
+
if (config.broadcastChannels && config.broadcastChannels.length > 0) {
|
|
1737
|
+
try {
|
|
1738
|
+
await ctx.broadcast(config.broadcastChannels, newsText);
|
|
1739
|
+
} catch (err) {
|
|
1740
|
+
logger.warn(`新闻播报广播失败:`, err);
|
|
1741
|
+
}
|
|
1742
|
+
}
|
|
1743
|
+
}
|
|
1744
|
+
__name(broadcastMacroNews, "broadcastMacroNews");
|
|
1676
1745
|
const patternsByCategory = {
|
|
1677
1746
|
bullish: [],
|
|
1678
1747
|
bearish: [],
|
|
@@ -1821,6 +1890,7 @@ function apply(ctx, config) {
|
|
|
1821
1890
|
}, "createAutoState");
|
|
1822
1891
|
if (needNewState) {
|
|
1823
1892
|
await createAutoState();
|
|
1893
|
+
await broadcastMacroNews(state.targetPrice, currentPrice);
|
|
1824
1894
|
}
|
|
1825
1895
|
const basePrice = state.startPrice;
|
|
1826
1896
|
const targetPrice = state.targetPrice;
|
|
@@ -2074,13 +2144,17 @@ function apply(ctx, config) {
|
|
|
2074
2144
|
} else {
|
|
2075
2145
|
newEndTime = new Date(now.getTime() + 7 * 24 * 3600 * 1e3);
|
|
2076
2146
|
}
|
|
2077
|
-
await ctx.database.set(
|
|
2078
|
-
|
|
2079
|
-
|
|
2080
|
-
|
|
2081
|
-
|
|
2082
|
-
|
|
2083
|
-
|
|
2147
|
+
await ctx.database.set(
|
|
2148
|
+
"bourse_state",
|
|
2149
|
+
{ key: "macro_state" },
|
|
2150
|
+
{
|
|
2151
|
+
startPrice: currentPrice,
|
|
2152
|
+
targetPrice: fmtPrice(newTargetPrice),
|
|
2153
|
+
lastCycleStart: now,
|
|
2154
|
+
endTime: newEndTime,
|
|
2155
|
+
lastDividendDate: now
|
|
2156
|
+
}
|
|
2157
|
+
);
|
|
2084
2158
|
switchKLinePattern("分红除息");
|
|
2085
2159
|
logger.info(
|
|
2086
2160
|
`分红引擎: 执行完毕 | 除息前股价=${oldPrice} -> 除息后=${currentPrice} (${(-priceDropRate * 100).toFixed(2)}%) | 派发成功=${successCount}人 | 失败=${failCount}人 | 合计派发=${totalDividendPaid.toFixed(2)} ${config.currency}`
|
|
@@ -2140,7 +2214,8 @@ function apply(ctx, config) {
|
|
|
2140
2214
|
getDailyOpenPrice,
|
|
2141
2215
|
setWasMarketOpen,
|
|
2142
2216
|
isMarketOpen,
|
|
2143
|
-
switchKLinePattern
|
|
2217
|
+
switchKLinePattern,
|
|
2218
|
+
broadcastMacroNews
|
|
2144
2219
|
});
|
|
2145
2220
|
registerTestCommands({
|
|
2146
2221
|
ctx,
|
package/package.json
CHANGED
package/readme.md
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
|
|
7
7
|
本插件模拟了一个具备自动宏观调控、25种经典K线形态、智能概率博弈和可视化交割单的深度拟真股票市场。用户可以使用机器人通用的货币(如信用点)进行股票买卖、炒股理财。
|
|
8
8
|
|
|
9
|
-
> 版本:**3.0.0-alpha.
|
|
9
|
+
> 版本:**3.0.0-alpha.19**
|
|
10
10
|
|
|
11
11
|
## ✨ 特性
|
|
12
12
|
|
|
@@ -129,6 +129,8 @@ A: 股价采用 **"智能期望模型"** 驱动,更贴近真实博弈:
|
|
|
129
129
|
### 交易时间
|
|
130
130
|
- **openHour**: 每日开市时间(小时,0-23,默认 `8` 点)。
|
|
131
131
|
- **closeHour**: 每日休市时间(小时,0-23,默认 `23` 点)。
|
|
132
|
+
|
|
133
|
+
### 股市开关
|
|
132
134
|
- **marketStatus**: 股市总开关,可选 `open` (强制开启)、`close` (强制关闭)、`auto` (自动按时间)。
|
|
133
135
|
|
|
134
136
|
### 冻结机制
|
|
@@ -137,7 +139,9 @@ A: 股价采用 **"智能期望模型"** 驱动,更贴近真实博弈:
|
|
|
137
139
|
- **maxFreezeTime**: 最大冻结时间(分钟,默认 `1440` 即24小时)。
|
|
138
140
|
|
|
139
141
|
### 手续费与精度
|
|
140
|
-
- **
|
|
142
|
+
- **sellFeeTiers**: 卖出手续费分档列表(默认 `[{ minAmount: 1, feePercent: 0 }]`)。
|
|
143
|
+
- **minAmount**: 起始股数(含)。
|
|
144
|
+
- **feePercent**: 手续费比例(%)。
|
|
141
145
|
- **precisionInteger**: 是否启用整数精度(默认 `false`)。
|
|
142
146
|
|
|
143
147
|
### 开发者选项
|
|
@@ -148,6 +152,44 @@ A: 股价采用 **"智能期望模型"** 驱动,更贴近真实博弈:
|
|
|
148
152
|
- **fixedUpdateHour**: 固定更新时间(小时,0-23,默认 `9`)。仅在 `fixedUpdateTime` 为 `true` 时生效。
|
|
149
153
|
- **biasMax**: 宏观期望上下偏倚的最大值(默认 `0.45`)。
|
|
150
154
|
|
|
155
|
+
### 分红机制
|
|
156
|
+
- **dividendIntervalDays**: 分红结算周期(天,默认 `7`)。
|
|
157
|
+
- **maxDividendRate**: 最大分红期望利润率(0-1,默认 `0.15`,超出部分用于除息而非派发)。
|
|
158
|
+
|
|
159
|
+
### 新闻播报机制
|
|
160
|
+
- **newsDeviationThreshold**: 触发新闻的偏离度阈值(默认 `0.15`,例如 `0.15` 表示偏离 15% 以上触发)。
|
|
161
|
+
- **broadcastChannels**: 播报新闻的频道/群聊 ID 列表(为空则仅后台日志,不发送群消息)。
|
|
162
|
+
- **positiveNews**: 利好新闻列表(表格配置)。
|
|
163
|
+
- **negativeNews**: 利空新闻列表(表格配置)。
|
|
164
|
+
- **text**: 新闻文本,可使用 `{stockName}` 作为股票名称占位符。
|
|
165
|
+
- **weight**: 权重(整数,最小 `1`,数值越大越容易被选中)。
|
|
166
|
+
|
|
167
|
+
### 开发者选项
|
|
168
|
+
- **enableDebug**: 是否启用调试模式(默认 `false`)。开启后可使用 `bourse.test.*` 系列调试指令。
|
|
169
|
+
|
|
170
|
+
### 配置示例
|
|
171
|
+
```yaml
|
|
172
|
+
sellFeeTiers:
|
|
173
|
+
- minAmount: 1
|
|
174
|
+
feePercent: 0.6
|
|
175
|
+
- minAmount: 200
|
|
176
|
+
feePercent: 0.3
|
|
177
|
+
|
|
178
|
+
newsDeviationThreshold: 0.15
|
|
179
|
+
broadcastChannels:
|
|
180
|
+
- "123456789"
|
|
181
|
+
positiveNews:
|
|
182
|
+
- text: "【财经快讯】{stockName} 宣布取得重大技术突破,预期利润大增!"
|
|
183
|
+
weight: 3
|
|
184
|
+
- text: "【市场异动】神秘巨头入局,{stockName} 获大额资本注资!"
|
|
185
|
+
weight: 1
|
|
186
|
+
negativeNews:
|
|
187
|
+
- text: "【黑天鹅】{stockName} 遭遇大规模不可抗力打击,市场恐慌情绪蔓延!"
|
|
188
|
+
weight: 2
|
|
189
|
+
- text: "【行业悲报】{stockName} 最新季度财报严重不及预期,高管集体减持!"
|
|
190
|
+
weight: 1
|
|
191
|
+
```
|
|
192
|
+
|
|
151
193
|
## 📝 更新日志
|
|
152
194
|
|
|
153
195
|
详细的更新日志请查看 [CHANGELOG.md](./CHANGELOG.md)。
|