apexbot 1.0.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.
- package/LICENSE +21 -0
- package/README.md +307 -0
- package/dist/adapters/manifold.js +166 -0
- package/dist/adapters/telegram.js +133 -0
- package/dist/agent/agentManager.js +315 -0
- package/dist/backtest/backtester.js +24 -0
- package/dist/channels/channelManager.js +72 -0
- package/dist/channels/discord.js +136 -0
- package/dist/channels/telegram.js +186 -0
- package/dist/cli/index.js +838 -0
- package/dist/core/eventBus.js +33 -0
- package/dist/decisionEngine.js +69 -0
- package/dist/eventBus.js +21 -0
- package/dist/gateway/dashboard.js +1009 -0
- package/dist/gateway/index.js +303 -0
- package/dist/index.js +195 -0
- package/dist/math/ev.js +25 -0
- package/dist/math/kelly.js +24 -0
- package/dist/rateLimiter.js +42 -0
- package/dist/safety/failsafe.js +32 -0
- package/dist/safety/llmChecker.js +148 -0
- package/dist/sessions/sessionManager.js +120 -0
- package/dist/strategy/arbitrage.js +151 -0
- package/package.json +78 -0
- package/scripts/install.ps1 +114 -0
- package/scripts/install.sh +146 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 ApexBot Contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,307 @@
|
|
|
1
|
+
# 🦊 ApexBot — Your Free, Private AI Assistant
|
|
2
|
+
|
|
3
|
+
<div align="center">
|
|
4
|
+
|
|
5
|
+
```
|
|
6
|
+
___ ____ _______ ______ ____ ______
|
|
7
|
+
/ | / __ \/ ____/ |/ / __ )/ __ \/_ __/
|
|
8
|
+
/ /| | / /_/ / __/ | / __ / / / / / /
|
|
9
|
+
/ ___ |/ ____/ /___ / / /_/ / /_/ / / /
|
|
10
|
+
/_/ |_/_/ /_____//_/|_/_____/\____/ /_/
|
|
11
|
+
|
|
12
|
+
🦊 Your Free AI Assistant 🦊
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
[](https://github.com/YOUR_USERNAME/apexbot/actions)
|
|
16
|
+
[](https://www.npmjs.com/package/apexbot)
|
|
17
|
+
[](LICENSE)
|
|
18
|
+
[](https://www.typescriptlang.org/)
|
|
19
|
+
|
|
20
|
+
**100% Free • Open Source • Private • Self-Hosted**
|
|
21
|
+
|
|
22
|
+
[Installation](#-installation) • [Features](#-features) • [Quick Start](#-quick-start) • [Commands](#-commands) • [Contributing](#-contributing)
|
|
23
|
+
|
|
24
|
+
</div>
|
|
25
|
+
|
|
26
|
+
---
|
|
27
|
+
|
|
28
|
+
## ⚡ Installation
|
|
29
|
+
|
|
30
|
+
### One-Line Install
|
|
31
|
+
|
|
32
|
+
**Windows (PowerShell):**
|
|
33
|
+
```powershell
|
|
34
|
+
iwr -useb https://raw.githubusercontent.com/YOUR_USERNAME/apexbot/main/scripts/install.ps1 | iex
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
**macOS/Linux:**
|
|
38
|
+
```bash
|
|
39
|
+
curl -fsSL https://raw.githubusercontent.com/YOUR_USERNAME/apexbot/main/scripts/install.sh | bash
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
**npm (global):**
|
|
43
|
+
```bash
|
|
44
|
+
npm install -g apexbot
|
|
45
|
+
apexbot onboard
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
### Manual Install
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
# Clone repository
|
|
52
|
+
git clone https://github.com/YOUR_USERNAME/apexbot.git
|
|
53
|
+
cd apexbot
|
|
54
|
+
npm install
|
|
55
|
+
npm run build
|
|
56
|
+
|
|
57
|
+
# Run setup wizard
|
|
58
|
+
npm run onboard
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
---
|
|
62
|
+
|
|
63
|
+
## ✨ Features
|
|
64
|
+
|
|
65
|
+
### 🤖 100% Free AI with Ollama
|
|
66
|
+
- **No API keys needed** — runs completely locally
|
|
67
|
+
- **No cloud costs** — your hardware, your AI
|
|
68
|
+
- **Private** — conversations never leave your machine
|
|
69
|
+
- **Multiple models** — llama3.2, mistral, codellama, qwen2.5
|
|
70
|
+
|
|
71
|
+
### 📱 Multi-Channel Support
|
|
72
|
+
| Channel | Status | Description |
|
|
73
|
+
|---------|--------|-------------|
|
|
74
|
+
| **Telegram** | ✅ Ready | Full bot integration |
|
|
75
|
+
| **Discord** | ✅ Ready | Guilds and DMs |
|
|
76
|
+
| **WebChat** | ✅ Ready | Built-in web dashboard |
|
|
77
|
+
| **WhatsApp** | 🚧 Soon | Via Baileys |
|
|
78
|
+
|
|
79
|
+
### 🧠 AI Providers
|
|
80
|
+
| Provider | Cost | Description |
|
|
81
|
+
|----------|------|-------------|
|
|
82
|
+
| **Ollama** | **FREE** | Local AI (recommended!) |
|
|
83
|
+
| Google Gemini | Free tier | Cloud AI |
|
|
84
|
+
| Anthropic Claude | Paid | Cloud AI |
|
|
85
|
+
| OpenAI GPT | Paid | Cloud AI |
|
|
86
|
+
|
|
87
|
+
### 🛡️ Self-Hosted & Private
|
|
88
|
+
- Your data stays with you
|
|
89
|
+
- No telemetry or tracking
|
|
90
|
+
- Full control over your bot
|
|
91
|
+
|
|
92
|
+
---
|
|
93
|
+
|
|
94
|
+
## 🚀 Quick Start
|
|
95
|
+
|
|
96
|
+
### 1. Install Ollama (for free AI)
|
|
97
|
+
|
|
98
|
+
**Windows:**
|
|
99
|
+
```powershell
|
|
100
|
+
winget install Ollama.Ollama
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
**macOS:**
|
|
104
|
+
```bash
|
|
105
|
+
brew install ollama
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
**Linux:**
|
|
109
|
+
```bash
|
|
110
|
+
curl -fsSL https://ollama.com/install.sh | sh
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
### 2. Pull a model
|
|
114
|
+
|
|
115
|
+
```bash
|
|
116
|
+
ollama pull llama3.2
|
|
117
|
+
ollama serve # Keep running in background
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
### 3. Install ApexBot
|
|
121
|
+
|
|
122
|
+
```bash
|
|
123
|
+
npm install -g apexbot
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
### 4. Run setup wizard
|
|
127
|
+
|
|
128
|
+
```bash
|
|
129
|
+
apexbot onboard
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
The wizard will guide you through:
|
|
133
|
+
- Choosing AI provider (Ollama recommended!)
|
|
134
|
+
- Setting up Telegram/Discord
|
|
135
|
+
- Configuring your bot
|
|
136
|
+
|
|
137
|
+
### 5. Start your bot
|
|
138
|
+
|
|
139
|
+
```bash
|
|
140
|
+
apexbot daemon start
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
Done! 🎉 Your bot is now running.
|
|
144
|
+
|
|
145
|
+
---
|
|
146
|
+
|
|
147
|
+
## 🎮 Commands
|
|
148
|
+
|
|
149
|
+
### CLI Commands
|
|
150
|
+
|
|
151
|
+
```bash
|
|
152
|
+
# Setup & Configuration
|
|
153
|
+
apexbot onboard # Interactive setup wizard
|
|
154
|
+
apexbot config # Show configuration
|
|
155
|
+
apexbot config --reset # Reset configuration
|
|
156
|
+
|
|
157
|
+
# Daemon (background service)
|
|
158
|
+
apexbot daemon start # Start in background
|
|
159
|
+
apexbot daemon stop # Stop daemon
|
|
160
|
+
apexbot daemon restart # Restart daemon
|
|
161
|
+
apexbot daemon status # Check status
|
|
162
|
+
|
|
163
|
+
# Gateway (foreground)
|
|
164
|
+
apexbot gateway # Start gateway server
|
|
165
|
+
apexbot gateway --verbose # With debug logs
|
|
166
|
+
|
|
167
|
+
# Other
|
|
168
|
+
apexbot status # Show status
|
|
169
|
+
apexbot models # Manage Ollama models
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
### Chat Commands
|
|
173
|
+
|
|
174
|
+
| Command | Description |
|
|
175
|
+
|---------|-------------|
|
|
176
|
+
| `/help` | Show available commands |
|
|
177
|
+
| `/status` | Show session info |
|
|
178
|
+
| `/new` | Start new conversation |
|
|
179
|
+
| `/model <name>` | Switch AI model |
|
|
180
|
+
|
|
181
|
+
---
|
|
182
|
+
|
|
183
|
+
## 🏗️ Architecture
|
|
184
|
+
|
|
185
|
+
```
|
|
186
|
+
┌─────────────────────────────────────────────────────────────┐
|
|
187
|
+
│ Messaging Channels │
|
|
188
|
+
│ Telegram │ Discord │ WebChat │ WhatsApp │
|
|
189
|
+
└────────────┬─────────┬─────────┬─────────┬──────────────────┘
|
|
190
|
+
│ │ │ │
|
|
191
|
+
▼ ▼ ▼ ▼
|
|
192
|
+
┌─────────────────────────────────────────────────────────────┐
|
|
193
|
+
│ Gateway Server │
|
|
194
|
+
│ (HTTP + WebSocket on port 18789) │
|
|
195
|
+
├─────────────────────────────────────────────────────────────┤
|
|
196
|
+
│ Sessions Manager │ Event Bus │ Rate Limiter │
|
|
197
|
+
└────────────────────┼─────────────┼──────────────────────────┘
|
|
198
|
+
│ │
|
|
199
|
+
▼ ▼
|
|
200
|
+
┌─────────────────────────────────────────────────────────────┐
|
|
201
|
+
│ AI Agent Manager │
|
|
202
|
+
│ Ollama │ Gemini │ Claude │ OpenAI │
|
|
203
|
+
└─────────────────────────────────────────────────────────────┘
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
---
|
|
207
|
+
|
|
208
|
+
## 🆚 ApexBot vs Clawdbot
|
|
209
|
+
|
|
210
|
+
| Feature | Clawdbot | ApexBot |
|
|
211
|
+
|---------|----------|---------|
|
|
212
|
+
| **Cost** | Cloud APIs (paid) | **100% FREE with Ollama** |
|
|
213
|
+
| **Privacy** | Cloud-dependent | **Fully local & private** |
|
|
214
|
+
| **Channels** | WhatsApp, Telegram, Discord, iMessage | Telegram, Discord, WebChat |
|
|
215
|
+
| **AI** | Claude, GPT | **Ollama (free!)**, Gemini, Claude, GPT |
|
|
216
|
+
| **Setup** | Complex | **Simple wizard** |
|
|
217
|
+
| **License** | Proprietary | **MIT (Open Source)** |
|
|
218
|
+
|
|
219
|
+
---
|
|
220
|
+
|
|
221
|
+
## 📁 Project Structure
|
|
222
|
+
|
|
223
|
+
```
|
|
224
|
+
apexbot/
|
|
225
|
+
├── src/
|
|
226
|
+
│ ├── cli/ # Command-line interface
|
|
227
|
+
│ ├── gateway/ # HTTP/WebSocket server & dashboard
|
|
228
|
+
│ ├── channels/ # Telegram, Discord, WebChat
|
|
229
|
+
│ ├── agent/ # AI provider integrations
|
|
230
|
+
│ ├── sessions/ # Conversation management
|
|
231
|
+
│ └── core/ # Event bus, utilities
|
|
232
|
+
├── scripts/
|
|
233
|
+
│ ├── install.ps1 # Windows installer
|
|
234
|
+
│ └── install.sh # macOS/Linux installer
|
|
235
|
+
├── package.json
|
|
236
|
+
└── README.md
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
---
|
|
240
|
+
|
|
241
|
+
## 🔧 Configuration
|
|
242
|
+
|
|
243
|
+
Configuration is stored in `~/.apexbot/config.json`:
|
|
244
|
+
|
|
245
|
+
```json
|
|
246
|
+
{
|
|
247
|
+
"gateway": {
|
|
248
|
+
"port": 18789
|
|
249
|
+
},
|
|
250
|
+
"agent": {
|
|
251
|
+
"provider": "ollama",
|
|
252
|
+
"apiUrl": "http://localhost:11434",
|
|
253
|
+
"model": "llama3.2"
|
|
254
|
+
},
|
|
255
|
+
"channels": {
|
|
256
|
+
"telegram": {
|
|
257
|
+
"token": "your-bot-token"
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
Or use environment variables:
|
|
264
|
+
|
|
265
|
+
```bash
|
|
266
|
+
export OLLAMA_URL=http://localhost:11434
|
|
267
|
+
export OLLAMA_MODEL=llama3.2
|
|
268
|
+
export TELEGRAM_BOT_TOKEN=your-token
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
---
|
|
272
|
+
|
|
273
|
+
## 🤝 Contributing
|
|
274
|
+
|
|
275
|
+
Contributions are welcome! See [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines.
|
|
276
|
+
|
|
277
|
+
```bash
|
|
278
|
+
# Development
|
|
279
|
+
git clone https://github.com/YOUR_USERNAME/apexbot.git
|
|
280
|
+
cd apexbot
|
|
281
|
+
npm install
|
|
282
|
+
npm run dev # Start with hot-reload
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
---
|
|
286
|
+
|
|
287
|
+
## 📄 License
|
|
288
|
+
|
|
289
|
+
MIT License — see [LICENSE](LICENSE) for details.
|
|
290
|
+
|
|
291
|
+
---
|
|
292
|
+
|
|
293
|
+
## 🙏 Acknowledgments
|
|
294
|
+
|
|
295
|
+
- Inspired by [Clawdbot](https://github.com/clawdbot/clawdbot)
|
|
296
|
+
- Powered by [Ollama](https://ollama.com) for free local AI
|
|
297
|
+
- Built with TypeScript, grammY, discord.js
|
|
298
|
+
|
|
299
|
+
---
|
|
300
|
+
|
|
301
|
+
<div align="center">
|
|
302
|
+
|
|
303
|
+
**Made with ❤️ by the ApexBot community**
|
|
304
|
+
|
|
305
|
+
⭐ Star this repo if you find it useful!
|
|
306
|
+
|
|
307
|
+
</div>
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.ManifoldAdapter = void 0;
|
|
7
|
+
const axios_1 = __importDefault(require("axios"));
|
|
8
|
+
const ws_1 = __importDefault(require("ws"));
|
|
9
|
+
const eventBus_1 = require("../eventBus");
|
|
10
|
+
const rateLimiter_1 = __importDefault(require("../rateLimiter"));
|
|
11
|
+
class ManifoldAdapter {
|
|
12
|
+
http;
|
|
13
|
+
ws = null;
|
|
14
|
+
cfg;
|
|
15
|
+
limiter;
|
|
16
|
+
reconnectAttempts = 0;
|
|
17
|
+
maxReconnectAttempts = 10;
|
|
18
|
+
subscribedMarkets = new Set();
|
|
19
|
+
constructor(cfg) {
|
|
20
|
+
this.cfg = {
|
|
21
|
+
baseUrl: 'https://api.manifold.markets/v0',
|
|
22
|
+
wsUrl: 'wss://api.manifold.markets/ws',
|
|
23
|
+
...cfg,
|
|
24
|
+
};
|
|
25
|
+
this.http = axios_1.default.create({
|
|
26
|
+
baseURL: this.cfg.baseUrl,
|
|
27
|
+
headers: cfg.apiKey ? { Authorization: `Key ${cfg.apiKey}` } : {},
|
|
28
|
+
});
|
|
29
|
+
// Manifold: ~1000 req/min → ~16/sec; be conservative
|
|
30
|
+
this.limiter = new rateLimiter_1.default(20, 10);
|
|
31
|
+
}
|
|
32
|
+
// ─────────────────────────────────────────────────────────────────
|
|
33
|
+
// REST API Methods
|
|
34
|
+
// ─────────────────────────────────────────────────────────────────
|
|
35
|
+
async request(method, path, data) {
|
|
36
|
+
// Rate limit check
|
|
37
|
+
const waitTime = this.limiter.timeUntil(1);
|
|
38
|
+
if (waitTime > 0) {
|
|
39
|
+
await new Promise((r) => setTimeout(r, waitTime * 1000));
|
|
40
|
+
}
|
|
41
|
+
this.limiter.tryRemove(1);
|
|
42
|
+
const res = await this.http.request({ method, url: path, data });
|
|
43
|
+
return res.data;
|
|
44
|
+
}
|
|
45
|
+
async getMarkets(limit = 100) {
|
|
46
|
+
return this.request('get', `/markets?limit=${limit}`);
|
|
47
|
+
}
|
|
48
|
+
async getMarket(id) {
|
|
49
|
+
return this.request('get', `/market/${id}`);
|
|
50
|
+
}
|
|
51
|
+
async searchMarkets(term, limit = 50) {
|
|
52
|
+
return this.request('get', `/search-markets?term=${encodeURIComponent(term)}&limit=${limit}`);
|
|
53
|
+
}
|
|
54
|
+
async getMarketBySlug(slug) {
|
|
55
|
+
return this.request('get', `/slug/${slug}`);
|
|
56
|
+
}
|
|
57
|
+
async getMyBets(limit = 100) {
|
|
58
|
+
return this.request('get', `/bets?limit=${limit}`);
|
|
59
|
+
}
|
|
60
|
+
async getMe() {
|
|
61
|
+
return this.request('get', '/me');
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Place a bet on a market.
|
|
65
|
+
* @param marketId Market ID
|
|
66
|
+
* @param amount Amount in Mana (M$)
|
|
67
|
+
* @param outcome 'YES' or 'NO'
|
|
68
|
+
* @param limitProb Optional limit probability (0..1)
|
|
69
|
+
*/
|
|
70
|
+
async placeBet(marketId, amount, outcome, limitProb) {
|
|
71
|
+
const payload = { contractId: marketId, amount, outcome };
|
|
72
|
+
if (limitProb !== undefined) {
|
|
73
|
+
payload.limitProb = limitProb;
|
|
74
|
+
}
|
|
75
|
+
const bet = await this.request('post', '/bet', payload);
|
|
76
|
+
(0, eventBus_1.emit)('order:placed', { marketId, side: outcome === 'YES' ? 'buy' : 'sell', stake: amount, betId: bet.id });
|
|
77
|
+
return bet;
|
|
78
|
+
}
|
|
79
|
+
async cancelBet(betId) {
|
|
80
|
+
await this.request('post', `/bet/cancel/${betId}`);
|
|
81
|
+
}
|
|
82
|
+
// ─────────────────────────────────────────────────────────────────
|
|
83
|
+
// WebSocket for real-time updates
|
|
84
|
+
// ─────────────────────────────────────────────────────────────────
|
|
85
|
+
connectWebSocket() {
|
|
86
|
+
if (this.ws) {
|
|
87
|
+
this.ws.close();
|
|
88
|
+
}
|
|
89
|
+
console.log('📡 Connecting to Manifold WebSocket...');
|
|
90
|
+
this.ws = new ws_1.default(this.cfg.wsUrl);
|
|
91
|
+
this.ws.on('open', () => {
|
|
92
|
+
console.log('✅ Manifold WebSocket connected');
|
|
93
|
+
this.reconnectAttempts = 0;
|
|
94
|
+
// Re-subscribe to markets
|
|
95
|
+
for (const marketId of this.subscribedMarkets) {
|
|
96
|
+
this.subscribeMarket(marketId);
|
|
97
|
+
}
|
|
98
|
+
});
|
|
99
|
+
this.ws.on('message', (data) => {
|
|
100
|
+
try {
|
|
101
|
+
const msg = JSON.parse(data.toString());
|
|
102
|
+
this.handleWsMessage(msg);
|
|
103
|
+
}
|
|
104
|
+
catch (e) {
|
|
105
|
+
console.error('WS parse error:', e);
|
|
106
|
+
}
|
|
107
|
+
});
|
|
108
|
+
this.ws.on('close', () => {
|
|
109
|
+
console.log('🔌 Manifold WebSocket closed');
|
|
110
|
+
this.scheduleReconnect();
|
|
111
|
+
});
|
|
112
|
+
this.ws.on('error', (err) => {
|
|
113
|
+
console.error('WS error:', err);
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
scheduleReconnect() {
|
|
117
|
+
if (this.reconnectAttempts >= this.maxReconnectAttempts) {
|
|
118
|
+
(0, eventBus_1.emit)('strategy:alert', 'ws:max_reconnect_exceeded');
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
const delay = Math.min(1000 * 2 ** this.reconnectAttempts, 30000);
|
|
122
|
+
this.reconnectAttempts++;
|
|
123
|
+
console.log(`Reconnecting in ${delay}ms (attempt ${this.reconnectAttempts})...`);
|
|
124
|
+
setTimeout(() => this.connectWebSocket(), delay);
|
|
125
|
+
}
|
|
126
|
+
handleWsMessage(msg) {
|
|
127
|
+
// Manifold WS message types: 'market', 'bet', etc.
|
|
128
|
+
switch (msg.type) {
|
|
129
|
+
case 'market':
|
|
130
|
+
(0, eventBus_1.emit)('market:update', {
|
|
131
|
+
marketId: msg.market?.id,
|
|
132
|
+
price: msg.market?.probability,
|
|
133
|
+
description: msg.market?.question,
|
|
134
|
+
timestamp: Date.now(),
|
|
135
|
+
});
|
|
136
|
+
break;
|
|
137
|
+
case 'bet':
|
|
138
|
+
// Someone placed a bet
|
|
139
|
+
(0, eventBus_1.emit)('market:bet', msg.bet);
|
|
140
|
+
break;
|
|
141
|
+
default:
|
|
142
|
+
// Unknown message type
|
|
143
|
+
break;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
subscribeMarket(marketId) {
|
|
147
|
+
this.subscribedMarkets.add(marketId);
|
|
148
|
+
if (this.ws && this.ws.readyState === ws_1.default.OPEN) {
|
|
149
|
+
this.ws.send(JSON.stringify({ type: 'subscribe', marketId }));
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
unsubscribeMarket(marketId) {
|
|
153
|
+
this.subscribedMarkets.delete(marketId);
|
|
154
|
+
if (this.ws && this.ws.readyState === ws_1.default.OPEN) {
|
|
155
|
+
this.ws.send(JSON.stringify({ type: 'unsubscribe', marketId }));
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
disconnect() {
|
|
159
|
+
if (this.ws) {
|
|
160
|
+
this.ws.close();
|
|
161
|
+
this.ws = null;
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
exports.ManifoldAdapter = ManifoldAdapter;
|
|
166
|
+
exports.default = ManifoldAdapter;
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.TelegramAdapter = void 0;
|
|
4
|
+
const grammy_1 = require("grammy");
|
|
5
|
+
const eventBus_1 = require("../eventBus");
|
|
6
|
+
class TelegramAdapter {
|
|
7
|
+
bot;
|
|
8
|
+
cfg;
|
|
9
|
+
constructor(cfg) {
|
|
10
|
+
this.cfg = cfg;
|
|
11
|
+
this.bot = new grammy_1.Bot(cfg.botToken);
|
|
12
|
+
this.setupHandlers();
|
|
13
|
+
this.setupEventListeners();
|
|
14
|
+
}
|
|
15
|
+
isAllowed(ctx) {
|
|
16
|
+
const userId = ctx.from?.id;
|
|
17
|
+
console.log(`[TG] User ID: ${userId}, Allowed: ${this.cfg.allowedUserIds}`);
|
|
18
|
+
if (!userId)
|
|
19
|
+
return false;
|
|
20
|
+
// Allow if list is empty (no restrictions) or user is in the list
|
|
21
|
+
if (this.cfg.allowedUserIds.length === 0)
|
|
22
|
+
return true;
|
|
23
|
+
return this.cfg.allowedUserIds.includes(userId);
|
|
24
|
+
}
|
|
25
|
+
setupHandlers() {
|
|
26
|
+
// Command: /start
|
|
27
|
+
this.bot.command('start', async (ctx) => {
|
|
28
|
+
console.log(`[TG] /start from ${ctx.from?.id}`);
|
|
29
|
+
if (!this.isAllowed(ctx)) {
|
|
30
|
+
await ctx.reply('⛔ Brak dostępu. Twoje ID: ' + ctx.from?.id);
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
await ctx.reply('🤖 *ApexBot* uruchomiony!\n\n' +
|
|
34
|
+
'Komendy:\n' +
|
|
35
|
+
'/status - stan bota i bankroll\n' +
|
|
36
|
+
'/markets - aktywne rynki\n' +
|
|
37
|
+
'/stop - zatrzymaj trading\n' +
|
|
38
|
+
'/start_trading - wznów trading\n' +
|
|
39
|
+
'/set_risk <0.1-1.0> - ustaw mnożnik ryzyka Kelly', { parse_mode: 'Markdown' });
|
|
40
|
+
});
|
|
41
|
+
// Command: /status
|
|
42
|
+
this.bot.command('status', async (ctx) => {
|
|
43
|
+
if (!this.isAllowed(ctx))
|
|
44
|
+
return;
|
|
45
|
+
(0, eventBus_1.emit)('telegram:status_request', { chatId: ctx.chat.id });
|
|
46
|
+
});
|
|
47
|
+
// Command: /markets
|
|
48
|
+
this.bot.command('markets', async (ctx) => {
|
|
49
|
+
if (!this.isAllowed(ctx))
|
|
50
|
+
return;
|
|
51
|
+
(0, eventBus_1.emit)('telegram:markets_request', { chatId: ctx.chat.id });
|
|
52
|
+
});
|
|
53
|
+
// Command: /stop
|
|
54
|
+
this.bot.command('stop', async (ctx) => {
|
|
55
|
+
if (!this.isAllowed(ctx))
|
|
56
|
+
return;
|
|
57
|
+
(0, eventBus_1.emit)('telegram:stop_trading', { chatId: ctx.chat.id });
|
|
58
|
+
await ctx.reply('🛑 Trading zatrzymany.');
|
|
59
|
+
});
|
|
60
|
+
// Command: /start_trading
|
|
61
|
+
this.bot.command('start_trading', async (ctx) => {
|
|
62
|
+
if (!this.isAllowed(ctx))
|
|
63
|
+
return;
|
|
64
|
+
(0, eventBus_1.emit)('telegram:start_trading', { chatId: ctx.chat.id });
|
|
65
|
+
await ctx.reply('▶️ Trading wznowiony.');
|
|
66
|
+
});
|
|
67
|
+
// Command: /set_risk <value>
|
|
68
|
+
this.bot.command('set_risk', async (ctx) => {
|
|
69
|
+
if (!this.isAllowed(ctx))
|
|
70
|
+
return;
|
|
71
|
+
const arg = ctx.message?.text?.split(' ')[1];
|
|
72
|
+
const value = parseFloat(arg || '');
|
|
73
|
+
if (isNaN(value) || value < 0.05 || value > 1.0) {
|
|
74
|
+
await ctx.reply('❌ Użycie: /set_risk <0.05-1.0>');
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
(0, eventBus_1.emit)('telegram:set_risk', { chatId: ctx.chat.id, riskMultiplier: value });
|
|
78
|
+
await ctx.reply(`✅ Risk multiplier ustawiony na ${value}`);
|
|
79
|
+
});
|
|
80
|
+
// Handle text messages (future: natural language commands)
|
|
81
|
+
this.bot.on('message:text', async (ctx) => {
|
|
82
|
+
if (!this.isAllowed(ctx))
|
|
83
|
+
return;
|
|
84
|
+
// Echo for now; could integrate LLM here
|
|
85
|
+
await ctx.reply(`Otrzymałem: ${ctx.message.text}`);
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
setupEventListeners() {
|
|
89
|
+
// Listen for events from decision engine and send notifications
|
|
90
|
+
(0, eventBus_1.on)('order:placed', (order) => {
|
|
91
|
+
this.broadcast(`📈 *Order placed*\nMarket: \`${order.marketId}\`\nSide: ${order.side}\nStake: M$${order.stake.toFixed(2)}`);
|
|
92
|
+
});
|
|
93
|
+
(0, eventBus_1.on)('order:filled', (fill) => {
|
|
94
|
+
this.broadcast(`✅ *Order filled*\nMarket: \`${fill.marketId}\`\nPnL: M$${fill.pnl?.toFixed(2) || '?'}`);
|
|
95
|
+
});
|
|
96
|
+
(0, eventBus_1.on)('strategy:alert', (msg) => {
|
|
97
|
+
// Filter important alerts
|
|
98
|
+
if (msg.startsWith('failsafe:') || msg.startsWith('arb:')) {
|
|
99
|
+
this.broadcast(`⚠️ *Alert*: ${msg}`);
|
|
100
|
+
}
|
|
101
|
+
});
|
|
102
|
+
(0, eventBus_1.on)('arb:opportunity', (arb) => {
|
|
103
|
+
this.broadcast(`🔥 *Arbitrage opportunity*\n` +
|
|
104
|
+
`Markets: ${arb.markets.join(', ')}\n` +
|
|
105
|
+
`Expected profit: M$${arb.expectedProfit.toFixed(2)}`);
|
|
106
|
+
});
|
|
107
|
+
(0, eventBus_1.on)('safety:warning', (warn) => {
|
|
108
|
+
this.broadcast(`🚨 *Safety warning*\nMarket: \`${warn.marketId}\`\nReason: ${warn.reason}`);
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
async broadcast(message) {
|
|
112
|
+
for (const userId of this.cfg.allowedUserIds) {
|
|
113
|
+
try {
|
|
114
|
+
await this.bot.api.sendMessage(userId, message, { parse_mode: 'Markdown' });
|
|
115
|
+
}
|
|
116
|
+
catch (e) {
|
|
117
|
+
console.error(`Failed to send to ${userId}:`, e);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
async sendTo(chatId, message) {
|
|
122
|
+
await this.bot.api.sendMessage(chatId, message, { parse_mode: 'Markdown' });
|
|
123
|
+
}
|
|
124
|
+
async start() {
|
|
125
|
+
console.log('🤖 Telegram bot starting...');
|
|
126
|
+
await this.bot.start();
|
|
127
|
+
}
|
|
128
|
+
stop() {
|
|
129
|
+
this.bot.stop();
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
exports.TelegramAdapter = TelegramAdapter;
|
|
133
|
+
exports.default = TelegramAdapter;
|