nexusbert commited on
Commit
96e0cc2
Β·
verified Β·
1 Parent(s): 93166a1

Upload 36 files

Browse files
api_server.py ADDED
@@ -0,0 +1,512 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from fastapi import FastAPI, BackgroundTasks, HTTPException
2
+ from pydantic import BaseModel
3
+ import uvicorn
4
+ import asyncio
5
+ import threading
6
+ import time
7
+ from datetime import datetime, timedelta
8
+ from typing import Dict, List, Optional
9
+ import yaml
10
+ import os
11
+ from dotenv import load_dotenv
12
+
13
+ from core.exchange import BybitExchange
14
+ from core.strategy import ScalpingStrategy
15
+ from core.risk import RiskManager
16
+ from core.data_engine import DataEngine
17
+ from core.trade_monitor import TradeMonitor
18
+ from core.websockets import BybitWebSocket
19
+ from services.logger import log, log_trade, log_performance
20
+ from services.telegram import send_telegram
21
+
22
+ load_dotenv()
23
+
24
+ app = FastAPI(title="Bybit Scalping Bot API", version="1.0.0")
25
+
26
+ class TradeSession(BaseModel):
27
+ symbol: str
28
+ duration_hours: int = 18
29
+ max_trades: Optional[int] = None
30
+
31
+ class BotStatus(BaseModel):
32
+ is_running: bool
33
+ active_sessions: List[Dict]
34
+ total_pnl: float
35
+ trades_today: int
36
+ uptime: str
37
+
38
+ # Global bot state
39
+ bot_instances = {}
40
+ active_sessions = {}
41
+ session_reports = {}
42
+
43
+ def load_config():
44
+ settings = yaml.safe_load(open("config/settings.yaml"))
45
+ pairs = yaml.safe_load(open("config/pairs.yaml"))["pairs"]
46
+ return settings, pairs
47
+
48
+ def create_bot_instance(symbol: str):
49
+ """Create a dedicated bot instance for a symbol"""
50
+ settings, pairs = load_config()
51
+
52
+ exchange = BybitExchange()
53
+ data_engine = DataEngine()
54
+ strategy = ScalpingStrategy(data_engine)
55
+ risk_manager = RiskManager(exchange)
56
+ monitor = TradeMonitor(exchange, strategy, risk_manager, data_engine)
57
+ ws_client = BybitWebSocket(callback=lambda data: handle_ws_data(data, symbol))
58
+
59
+ return {
60
+ 'exchange': exchange,
61
+ 'data_engine': data_engine,
62
+ 'strategy': strategy,
63
+ 'risk_manager': risk_manager,
64
+ 'monitor': monitor,
65
+ 'ws_client': ws_client,
66
+ 'symbol': symbol,
67
+ 'start_time': datetime.now(),
68
+ 'trades': [],
69
+ 'pnl': 0.0
70
+ }
71
+
72
+ def handle_ws_data(data, symbol):
73
+ """Handle WebSocket data for specific symbol"""
74
+ if symbol in bot_instances:
75
+ bot = bot_instances[symbol]
76
+ if "topic" in data:
77
+ topic = data["topic"]
78
+ payload = data["data"]
79
+
80
+ if topic.startswith("tickers."):
81
+ ticker_symbol = topic.split(".")[1]
82
+ if ticker_symbol == symbol:
83
+ bot['data_engine'].update_price(symbol, float(payload["lastPrice"]))
84
+
85
+ elif topic.startswith("kline."):
86
+ parts = topic.split(".")
87
+ interval = parts[1]
88
+ ticker_symbol = parts[2]
89
+ if ticker_symbol == symbol:
90
+ for candle in payload:
91
+ candle_data = {
92
+ 'timestamp': candle['start'],
93
+ 'open': float(candle['open']),
94
+ 'high': float(candle['high']),
95
+ 'low': float(candle['low']),
96
+ 'close': float(candle['close']),
97
+ 'volume': float(candle['volume'])
98
+ }
99
+ bot['data_engine'].update_candle(symbol, interval, candle_data)
100
+
101
+ async def run_trading_session(symbol: str, duration_hours: int, max_trades: Optional[int] = None):
102
+ """Run a trading session for a specific symbol"""
103
+ session_id = f"{symbol}_{int(time.time())}"
104
+
105
+ log(f"πŸš€ Starting trading session for {symbol} (Duration: {duration_hours}h)")
106
+
107
+ if symbol not in bot_instances:
108
+ bot_instances[symbol] = create_bot_instance(symbol)
109
+
110
+ bot = bot_instances[symbol]
111
+ active_sessions[session_id] = {
112
+ 'symbol': symbol,
113
+ 'start_time': datetime.now(),
114
+ 'end_time': datetime.now() + timedelta(hours=duration_hours),
115
+ 'duration_hours': duration_hours,
116
+ 'max_trades': max_trades,
117
+ 'trades_executed': 0,
118
+ 'pnl': 0.0,
119
+ 'status': 'running'
120
+ }
121
+
122
+ try:
123
+ # Start WebSocket
124
+ await bot['ws_client'].connect()
125
+ await asyncio.sleep(2)
126
+ await bot['ws_client'].subscribe_ticker([symbol])
127
+ await bot['ws_client'].subscribe_kline([symbol], ["1", "5"])
128
+ await bot['ws_client'].subscribe_orderbook([symbol], depth=25)
129
+ await bot['ws_client'].subscribe_trades([symbol])
130
+
131
+ # Start monitoring
132
+ monitor_task = asyncio.create_task(bot['monitor'].start_monitoring())
133
+
134
+ # Run for specified duration
135
+ end_time = datetime.now() + timedelta(hours=duration_hours)
136
+ trades_count = 0
137
+
138
+ while datetime.now() < end_time:
139
+ await asyncio.sleep(1)
140
+
141
+ # Check trade limits
142
+ if max_trades and trades_count >= max_trades:
143
+ log(f"🎯 Max trades reached for {symbol} session")
144
+ break
145
+
146
+ # Update session stats
147
+ session = active_sessions[session_id]
148
+ session['pnl'] = bot['risk_manager'].daily_pnl
149
+ session['trades_executed'] = len(bot['risk_manager'].trade_history)
150
+
151
+ # Stop monitoring
152
+ bot['monitor'].stop_monitoring()
153
+ await bot['ws_client'].close()
154
+
155
+ # Generate report
156
+ await generate_session_report(session_id)
157
+
158
+ except Exception as e:
159
+ log(f"❌ Error in trading session for {symbol}: {e}")
160
+ active_sessions[session_id]['status'] = 'error'
161
+
162
+ async def generate_session_report(session_id: str):
163
+ """Generate and send trading session report"""
164
+ if session_id not in active_sessions:
165
+ return
166
+
167
+ session = active_sessions[session_id]
168
+ symbol = session['symbol']
169
+
170
+ if symbol in bot_instances:
171
+ bot = bot_instances[symbol]
172
+ risk_manager = bot['risk_manager']
173
+
174
+ # Calculate session metrics
175
+ total_trades = len(risk_manager.trade_history)
176
+ winning_trades = sum(1 for trade in risk_manager.trade_history if trade['pnl'] > 0)
177
+ losing_trades = total_trades - winning_trades
178
+ win_rate = winning_trades / total_trades if total_trades > 0 else 0
179
+ total_pnl = sum(trade['pnl'] for trade in risk_manager.trade_history)
180
+
181
+ # Generate report
182
+ report = f"""
183
+ πŸ† TRADING SESSION REPORT - {symbol}
184
+ ═══════════════════════════════════════════
185
+
186
+ πŸ“Š Session Details:
187
+ β€’ Duration: {session['duration_hours']} hours
188
+ β€’ Start Time: {session['start_time'].strftime('%Y-%m-%d %H:%M:%S')}
189
+ β€’ End Time: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}
190
+
191
+ πŸ“ˆ Performance Metrics:
192
+ β€’ Total Trades: {total_trades}
193
+ β€’ Winning Trades: {winning_trades}
194
+ β€’ Losing Trades: {losing_trades}
195
+ β€’ Win Rate: {win_rate:.1%}
196
+ β€’ Total P&L: ${total_pnl:.2f}
197
+
198
+ 🎯 Risk Management:
199
+ β€’ Max Loss Limit: ${risk_manager.max_daily_loss}
200
+ β€’ Risk per Trade: {risk_manager.risk_per_trade*100}%
201
+ β€’ Leverage Used: {risk_manager.leverage}x
202
+
203
+ πŸ’Ž Trade Summary:
204
+ """
205
+
206
+ # Add individual trade details
207
+ for i, trade in enumerate(risk_manager.trade_history[-10:], 1): # Last 10 trades
208
+ pnl_emoji = "🟒" if trade['pnl'] > 0 else "πŸ”΄"
209
+ report += f"{i}. {trade['side']} @ ${trade['entry_price']:.2f} β†’ ${trade['exit_price']:.2f} {pnl_emoji} P&L: ${trade['pnl']:.2f}\n"
210
+
211
+ report += f"\n═══════════════════════════════════════════"
212
+
213
+ # Send to Telegram
214
+ send_telegram(report)
215
+
216
+ # Save report
217
+ session_reports[session_id] = {
218
+ 'session': session,
219
+ 'metrics': {
220
+ 'total_trades': total_trades,
221
+ 'win_rate': win_rate,
222
+ 'total_pnl': total_pnl,
223
+ 'winning_trades': winning_trades,
224
+ 'losing_trades': losing_trades
225
+ },
226
+ 'trades': risk_manager.trade_history,
227
+ 'report': report
228
+ }
229
+
230
+ log(f"πŸ“Š Session report generated for {symbol}")
231
+
232
+ # Mark session as completed
233
+ session['status'] = 'completed'
234
+ session['end_time'] = datetime.now()
235
+
236
+ @app.get("/")
237
+ async def root():
238
+ """API root endpoint"""
239
+ return {"message": "Bybit Scalping Bot API", "version": "1.0.0", "status": "running"}
240
+
241
+ @app.get("/status")
242
+ async def get_status():
243
+ """Get bot status"""
244
+ total_pnl = 0
245
+ total_trades = 0
246
+
247
+ for session in active_sessions.values():
248
+ if session['status'] == 'running':
249
+ total_pnl += session.get('pnl', 0)
250
+ total_trades += session.get('trades_executed', 0)
251
+
252
+ return BotStatus(
253
+ is_running=bool(active_sessions),
254
+ active_sessions=[
255
+ {
256
+ 'session_id': sid,
257
+ 'symbol': session['symbol'],
258
+ 'status': session['status'],
259
+ 'start_time': session['start_time'].isoformat(),
260
+ 'pnl': session.get('pnl', 0),
261
+ 'trades': session.get('trades_executed', 0)
262
+ }
263
+ for sid, session in active_sessions.items()
264
+ ],
265
+ total_pnl=total_pnl,
266
+ trades_today=total_trades,
267
+ uptime=str(datetime.now() - datetime.fromtimestamp(time.time()))
268
+ )
269
+
270
+ @app.post("/start/{symbol}")
271
+ async def start_symbol_trading(symbol: str, background_tasks: BackgroundTasks, duration_hours: int = 18, max_trades: Optional[int] = None):
272
+ """Start trading for a specific symbol"""
273
+ settings, configured_pairs = load_config()
274
+
275
+ if symbol not in configured_pairs:
276
+ raise HTTPException(status_code=400, detail=f"Symbol {symbol} not configured. Available: {configured_pairs}")
277
+
278
+ # Check if already running
279
+ for session in active_sessions.values():
280
+ if session['symbol'] == symbol and session['status'] == 'running':
281
+ raise HTTPException(status_code=400, detail=f"Trading already active for {symbol}")
282
+
283
+ # Start trading session
284
+ background_tasks.add_task(run_trading_session, symbol, duration_hours, max_trades)
285
+
286
+ message = f"πŸš€ Started trading session for {symbol} ({duration_hours}h duration)"
287
+ send_telegram(message)
288
+ log(message)
289
+
290
+ return {"message": message, "symbol": symbol, "duration_hours": duration_hours}
291
+
292
+ @app.post("/stop/{symbol}")
293
+ async def stop_symbol_trading(symbol: str):
294
+ """Stop trading for a specific symbol"""
295
+ stopped_sessions = []
296
+
297
+ for session_id, session in active_sessions.items():
298
+ if session['symbol'] == symbol and session['status'] == 'running':
299
+ session['status'] = 'stopped'
300
+ session['end_time'] = datetime.now()
301
+ stopped_sessions.append(session_id)
302
+
303
+ if symbol in bot_instances:
304
+ bot = bot_instances[symbol]
305
+ bot['monitor'].stop_monitoring()
306
+ await bot['ws_client'].close()
307
+
308
+ if stopped_sessions:
309
+ message = f"πŸ›‘ Stopped trading for {symbol}"
310
+ send_telegram(message)
311
+ log(message)
312
+ return {"message": message, "stopped_sessions": stopped_sessions}
313
+ else:
314
+ raise HTTPException(status_code=404, detail=f"No active trading session found for {symbol}")
315
+
316
+ @app.get("/sessions")
317
+ async def get_sessions():
318
+ """Get all trading sessions"""
319
+ return {
320
+ "active_sessions": active_sessions,
321
+ "completed_sessions": session_reports
322
+ }
323
+
324
+ @app.get("/report/{session_id}")
325
+ async def get_session_report(session_id: str):
326
+ """Get detailed report for a specific session"""
327
+ if session_id in session_reports:
328
+ return session_reports[session_id]
329
+ else:
330
+ raise HTTPException(status_code=404, detail="Session report not found")
331
+
332
+ @app.get("/logs/analysis")
333
+ async def get_analysis_logs(lines: int = 50):
334
+ """Get recent analysis logs"""
335
+ try:
336
+ log_file = "logs/scalper.log"
337
+ if os.path.exists(log_file):
338
+ with open(log_file, 'r') as f:
339
+ all_lines = f.readlines()
340
+ # Filter for analysis-related logs
341
+ analysis_lines = [line for line in all_lines if any(keyword in line for keyword in [
342
+ 'SIGNAL', 'EMA', 'RSI', 'volume', 'orderbook', 'analysis', 'strategy'
343
+ ])]
344
+ recent_lines = analysis_lines[-lines:]
345
+ return {
346
+ "logs": recent_lines,
347
+ "count": len(recent_lines),
348
+ "total_analysis_logs": len(analysis_lines)
349
+ }
350
+ else:
351
+ return {"error": "Log file not found", "logs": [], "count": 0}
352
+ except Exception as e:
353
+ raise HTTPException(status_code=500, detail=f"Error reading logs: {e}")
354
+
355
+ @app.get("/logs/live")
356
+ async def get_live_logs(lines: int = 20):
357
+ """Get recent live logs (streaming)"""
358
+ try:
359
+ log_file = "logs/scalper.log"
360
+ if os.path.exists(log_file):
361
+ with open(log_file, 'r') as f:
362
+ all_lines = f.readlines()
363
+ recent_lines = all_lines[-lines:]
364
+ return {
365
+ "logs": recent_lines,
366
+ "count": len(recent_lines),
367
+ "latest_timestamp": recent_lines[-1].split(' - ')[0] if recent_lines else None
368
+ }
369
+ else:
370
+ return {"error": "Log file not found", "logs": [], "count": 0}
371
+ except Exception as e:
372
+ raise HTTPException(status_code=500, detail=f"Error reading logs: {e}")
373
+
374
+ @app.post("/start_all")
375
+ async def start_all_pairs(background_tasks: BackgroundTasks, duration_hours: int = 18, max_trades: Optional[int] = None):
376
+ """Start trading sessions for all configured pairs"""
377
+ settings, configured_pairs = load_config()
378
+
379
+ started_sessions = []
380
+ failed_sessions = []
381
+
382
+ for symbol in configured_pairs:
383
+ # Check if already running
384
+ already_running = any(session['symbol'] == symbol and session['status'] == 'running'
385
+ for session in active_sessions.values())
386
+
387
+ if already_running:
388
+ failed_sessions.append({"symbol": symbol, "reason": "Already running"})
389
+ continue
390
+
391
+ try:
392
+ # Start trading session
393
+ background_tasks.add_task(run_trading_session, symbol, duration_hours, max_trades)
394
+ started_sessions.append({"symbol": symbol, "duration_hours": duration_hours})
395
+ except Exception as e:
396
+ failed_sessions.append({"symbol": symbol, "reason": str(e)})
397
+
398
+ message = f"πŸš€ Started trading sessions for {len(started_sessions)} pairs"
399
+ if started_sessions:
400
+ send_telegram(message)
401
+ log(message)
402
+
403
+ return {
404
+ "message": message,
405
+ "started_sessions": started_sessions,
406
+ "failed_sessions": failed_sessions,
407
+ "total_started": len(started_sessions),
408
+ "total_failed": len(failed_sessions)
409
+ }
410
+
411
+ @app.post("/stop_all")
412
+ async def stop_all_pairs():
413
+ """Stop trading sessions for all pairs"""
414
+ stopped_sessions = []
415
+
416
+ for session_id, session in list(active_sessions.items()):
417
+ if session['status'] == 'running':
418
+ session['status'] = 'stopped'
419
+ session['end_time'] = datetime.now()
420
+ stopped_sessions.append(session_id)
421
+
422
+ # Stop the actual trading
423
+ if session['symbol'] in bot_instances:
424
+ bot = bot_instances[session['symbol']]
425
+ bot['monitor'].stop_monitoring()
426
+ await bot['ws_client'].close()
427
+
428
+ if stopped_sessions:
429
+ message = f"πŸ›‘ Stopped all trading sessions ({len(stopped_sessions)} sessions)"
430
+ send_telegram(message)
431
+ log(message)
432
+ return {"message": message, "stopped_sessions": stopped_sessions}
433
+ else:
434
+ return {"message": "No active sessions to stop", "stopped_sessions": []}
435
+
436
+ @app.get("/analysis/status")
437
+ async def get_analysis_status():
438
+ """Get current analysis status for all active sessions"""
439
+ analysis_status = {}
440
+
441
+ for session_id, session in active_sessions.items():
442
+ if session['status'] == 'running' and session['symbol'] in bot_instances:
443
+ bot = bot_instances[session['symbol']]
444
+ symbol = session['symbol']
445
+
446
+ # Get current market data
447
+ try:
448
+ current_price = bot['data_engine'].get_prices(symbol, limit=1)
449
+ current_price = current_price[-1] if current_price else None
450
+ except:
451
+ current_price = None
452
+
453
+ # Get technical indicators
454
+ try:
455
+ ema_fast = bot['data_engine'].calculate_ema(symbol, "1", 9)
456
+ ema_slow = bot['data_engine'].calculate_ema(symbol, "1", 21)
457
+ rsi = bot['data_engine'].calculate_rsi(symbol, "1", 14)
458
+ volume_spike = bot['data_engine'].detect_volume_spike(symbol, "1", 1.3)
459
+ orderbook_imbalance = bot['data_engine'].get_orderbook_imbalance(symbol)
460
+ except:
461
+ ema_fast = ema_slow = rsi = volume_spike = orderbook_imbalance = None
462
+
463
+ analysis_status[symbol] = {
464
+ "session_id": session_id,
465
+ "current_price": current_price,
466
+ "indicators": {
467
+ "ema_9": ema_fast,
468
+ "ema_21": ema_slow,
469
+ "rsi_14": rsi,
470
+ "volume_spike": volume_spike,
471
+ "orderbook_imbalance": orderbook_imbalance
472
+ },
473
+ "strategy_conditions": {
474
+ "trend_up": ema_fast > ema_slow if ema_fast and ema_slow else None,
475
+ "rsi_valid": 40 <= rsi <= 70 if rsi else None,
476
+ "volume_confirmed": volume_spike,
477
+ "orderbook_aligned": abs(orderbook_imbalance or 0) > 0.15
478
+ },
479
+ "last_update": datetime.now().isoformat()
480
+ }
481
+
482
+ return {
483
+ "analysis_status": analysis_status,
484
+ "active_sessions": len(analysis_status),
485
+ "last_updated": datetime.now().isoformat()
486
+ }
487
+
488
+ @app.post("/emergency_stop")
489
+ async def emergency_stop():
490
+ """Emergency stop all trading"""
491
+ stopped_sessions = []
492
+
493
+ for session_id, session in active_sessions.items():
494
+ if session['status'] == 'running':
495
+ session['status'] = 'emergency_stop'
496
+ session['end_time'] = datetime.now()
497
+ stopped_sessions.append(session_id)
498
+
499
+ # Stop all monitors
500
+ for bot in bot_instances.values():
501
+ bot['monitor'].stop_monitoring()
502
+ await bot['ws_client'].close()
503
+
504
+ message = f"🚨 EMERGENCY STOP activated - All trading halted"
505
+ send_telegram(message)
506
+ log(message)
507
+
508
+ return {"message": message, "stopped_sessions": stopped_sessions}
509
+
510
+ if __name__ == "__main__":
511
+ log("πŸš€ Starting FastAPI server for Bybit Scalping Bot")
512
+ uvicorn.run(app, host="0.0.0.0", port=8000)
app.py ADDED
@@ -0,0 +1,194 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+ import subprocess
3
+ import os
4
+ import signal
5
+ import time
6
+ from threading import Thread
7
+ import requests
8
+
9
+ # Set page config
10
+ st.set_page_config(
11
+ page_title="Scalping Bot Control",
12
+ page_icon="πŸ€–",
13
+ layout="wide"
14
+ )
15
+
16
+ st.title("πŸ€– Bybit Scalping Bot Control Panel")
17
+
18
+ # Sidebar
19
+ st.sidebar.header("βš™οΈ Configuration")
20
+
21
+ # Environment variables setup
22
+ st.sidebar.subheader("πŸ”‘ API Configuration")
23
+ bybit_key = st.sidebar.text_input("Bybit API Key", type="password")
24
+ bybit_secret = st.sidebar.text_input("Bybit API Secret", type="password")
25
+ bybit_testnet = st.sidebar.checkbox("Use Testnet", value=False)
26
+ telegram_token = st.sidebar.text_input("Telegram Bot Token (optional)")
27
+ telegram_chat = st.sidebar.text_input("Telegram Chat ID (optional)")
28
+
29
+ if st.sidebar.button("πŸ’Ύ Save Configuration"):
30
+ # Save to .env file
31
+ env_content = f"""BYBIT_API_KEY={bybit_key}
32
+ BYBIT_API_SECRET={bybit_secret}
33
+ BYBIT_TESTNET={str(bybit_testnet).lower()}
34
+ TELEGRAM_BOT_TOKEN={telegram_token}
35
+ TELEGRAM_CHAT_ID={telegram_chat}
36
+ """
37
+ with open('.env', 'w') as f:
38
+ f.write(env_content)
39
+ st.sidebar.success("Configuration saved!")
40
+
41
+ # Main content
42
+ col1, col2, col3 = st.columns(3)
43
+
44
+ with col1:
45
+ st.subheader("πŸš€ Start Trading")
46
+ symbol = st.selectbox("Symbol", ["BTCUSDT", "ETHUSDT", "SOLUSDT"])
47
+ duration = st.slider("Duration (hours)", 1, 24, 18)
48
+ max_trades = st.number_input("Max Trades (optional)", min_value=1, value=50)
49
+
50
+ if st.button("▢️ Start Trading", key="start"):
51
+ try:
52
+ response = requests.post(f"http://localhost:8000/start/{symbol}",
53
+ params={"duration_hours": duration, "max_trades": max_trades})
54
+ if response.status_code == 200:
55
+ st.success(f"βœ… Started trading {symbol} for {duration} hours")
56
+ else:
57
+ st.error(f"❌ Failed to start: {response.text}")
58
+ except Exception as e:
59
+ st.error(f"❌ Error: {e}")
60
+
61
+ with col2:
62
+ st.subheader("πŸ›‘ Stop Trading")
63
+ stop_symbol = st.selectbox("Symbol to Stop", ["BTCUSDT", "ETHUSDT", "SOLUSDT"], key="stop_select")
64
+
65
+ if st.button("⏹️ Stop Trading", key="stop"):
66
+ try:
67
+ response = requests.post(f"http://localhost:8000/stop/{stop_symbol}")
68
+ if response.status_code == 200:
69
+ st.success(f"βœ… Stopped trading {stop_symbol}")
70
+ else:
71
+ st.error(f"❌ Failed to stop: {response.text}")
72
+ except Exception as e:
73
+ st.error(f"❌ Error: {e}")
74
+
75
+ with col3:
76
+ st.subheader("🚨 Emergency")
77
+ if st.button("🚨 EMERGENCY STOP ALL", key="emergency"):
78
+ try:
79
+ response = requests.post("http://localhost:8000/emergency_stop")
80
+ if response.status_code == 200:
81
+ st.error("🚨 ALL TRADING STOPPED!")
82
+ else:
83
+ st.error(f"❌ Failed: {response.text}")
84
+ except Exception as e:
85
+ st.error(f"❌ Error: {e}")
86
+
87
+ # Status section
88
+ st.header("πŸ“Š Bot Status")
89
+
90
+ if st.button("πŸ”„ Refresh Status"):
91
+ try:
92
+ response = requests.get("http://localhost:8000/status")
93
+ if response.status_code == 200:
94
+ status = response.json()
95
+
96
+ # Overall status
97
+ if status["is_running"]:
98
+ st.success("βœ… Bot is RUNNING")
99
+ else:
100
+ st.warning("⏸️ Bot is STOPPED")
101
+
102
+ st.metric("Total P&L", f"${status['total_pnl']:.2f}")
103
+ st.metric("Trades Today", status['trades_today'])
104
+
105
+ # Active sessions
106
+ if status["active_sessions"]:
107
+ st.subheader("🎯 Active Sessions")
108
+ for session in status["active_sessions"]:
109
+ with st.expander(f"{session['symbol']} - {session['status'].upper()}"):
110
+ st.write(f"**Session ID:** {session['session_id']}")
111
+ st.write(f"**Started:** {session['start_time'][:19]}")
112
+ st.write(f"**P&L:** ${session['pnl']:.2f}")
113
+ st.write(f"**Trades:** {session['trades']}")
114
+ else:
115
+ st.info("No active sessions")
116
+
117
+ else:
118
+ st.error(f"❌ Failed to get status: {response.status_code}")
119
+ except Exception as e:
120
+ st.error(f"❌ Connection error: {e}")
121
+
122
+ # Analysis section
123
+ st.header("πŸ” Live Analysis")
124
+
125
+ if st.button("πŸ“Š Refresh Analysis"):
126
+ try:
127
+ response = requests.get("http://localhost:8000/analysis/status")
128
+ if response.status_code == 200:
129
+ analysis = response.json()
130
+
131
+ for symbol, data in analysis["analysis_status"].items():
132
+ with st.expander(f"πŸ“ˆ {symbol} Analysis"):
133
+ col1, col2 = st.columns(2)
134
+
135
+ with col1:
136
+ st.metric("Current Price", f"${data['current_price']:.2f}" if data['current_price'] else "N/A")
137
+
138
+ indicators = data['indicators']
139
+ st.write("**Indicators:**")
140
+ st.write(f"EMA 9: {indicators['ema_9']:.4f}" if indicators['ema_9'] else "EMA 9: N/A")
141
+ st.write(f"EMA 21: {indicators['ema_21']:.4f}" if indicators['ema_21'] else "EMA 21: N/A")
142
+ st.write(f"RSI 14: {indicators['rsi_14']:.1f}" if indicators['rsi_14'] else "RSI 14: N/A")
143
+
144
+ with col2:
145
+ conditions = data['strategy_conditions']
146
+ st.write("**Strategy Conditions:**")
147
+ st.write(f"πŸ“ˆ Trend Up: {'βœ…' if conditions['trend_up'] else '❌'}")
148
+ st.write(f"πŸ“Š RSI Valid: {'βœ…' if conditions['rsi_valid'] else '❌'}")
149
+ st.write(f"πŸ’₯ Volume Spike: {'βœ…' if conditions['volume_spike'] else '❌'}")
150
+ st.write(f"🎯 Orderbook OK: {'βœ…' if conditions['orderbook_aligned'] else '❌'}")
151
+
152
+ all_conditions = all([conditions['trend_up'], conditions['rsi_valid'],
153
+ conditions['volume_spike'], conditions['orderbook_aligned']])
154
+
155
+ if all_conditions:
156
+ st.success("🎯 TRADE SIGNAL READY!")
157
+ else:
158
+ st.info("⏳ Waiting for conditions...")
159
+ else:
160
+ st.error(f"❌ Failed to get analysis: {response.status_code}")
161
+ except Exception as e:
162
+ st.error(f"❌ Connection error: {e}")
163
+
164
+ # Logs section
165
+ st.header("πŸ“‹ Recent Logs")
166
+
167
+ log_type = st.selectbox("Log Type", ["Live Logs", "Analysis Logs"])
168
+
169
+ if st.button("πŸ“– Refresh Logs"):
170
+ try:
171
+ if log_type == "Live Logs":
172
+ response = requests.get("http://localhost:8000/logs/live")
173
+ else:
174
+ response = requests.get("http://localhost:8000/logs/analysis")
175
+
176
+ if response.status_code == 200:
177
+ logs_data = response.json()
178
+
179
+ st.write(f"**Total {log_type}:** {logs_data['count']}")
180
+
181
+ logs_text = ""
182
+ for log_line in logs_data['logs'][-10:]: # Show last 10
183
+ logs_text += log_line
184
+
185
+ st.code(logs_text, language="text")
186
+ else:
187
+ st.error(f"❌ Failed to get logs: {response.status_code}")
188
+ except Exception as e:
189
+ st.error(f"❌ Connection error: {e}")
190
+
191
+ # Footer
192
+ st.markdown("---")
193
+ st.markdown("*πŸ€– Bybit Scalping Bot - FastAPI Control Interface*")
194
+ st.markdown("*Made with ❀️ for automated crypto trading*")
backtester/__pycache__/engine.cpython-312.pyc ADDED
Binary file (18.6 kB). View file
 
backtester/engine.py ADDED
@@ -0,0 +1,411 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import pandas as pd
2
+ import numpy as np
3
+ from typing import Dict, List, Optional, Any, Tuple
4
+ import logging
5
+ import yaml
6
+ from datetime import datetime, timedelta
7
+ import json
8
+ import os
9
+
10
+ from core.strategy import ScalpingStrategy
11
+ from core.data_engine import DataEngine
12
+ from core.risk import RiskManager
13
+ from services.logger import log
14
+
15
+ logger = logging.getLogger(__name__)
16
+
17
+ class BacktestingEngine:
18
+ def __init__(self):
19
+ self.settings = yaml.safe_load(open("config/settings.yaml"))
20
+ self.pairs = yaml.safe_load(open("config/pairs.yaml"))["pairs"]
21
+
22
+ self.initial_balance = 1000
23
+ self.fee_rate = 0.001
24
+ self.slippage = 0.0005
25
+
26
+ self.results = {}
27
+
28
+ def load_historical_data(self, symbol: str, interval: str = "1",
29
+ days: int = 30) -> Optional[pd.DataFrame]:
30
+ try:
31
+
32
+ periods = days * 24 * 60
33
+ base_price = 50000 if symbol.startswith('BTC') else 3000 if symbol.startswith('ETH') else 100
34
+
35
+ np.random.seed(42)
36
+
37
+ timestamps = pd.date_range(
38
+ start=datetime.now() - timedelta(days=days),
39
+ end=datetime.now(),
40
+ freq='1min'
41
+ )[:periods]
42
+
43
+ returns = np.random.normal(0, 0.001, periods)
44
+ prices = base_price * np.exp(np.cumsum(returns))
45
+
46
+ highs = prices * (1 + np.abs(np.random.normal(0, 0.002, periods)))
47
+ lows = prices * (1 - np.abs(np.random.normal(0, 0.002, periods)))
48
+ opens = np.roll(prices, 1)
49
+ opens[0] = base_price
50
+
51
+ volumes = np.random.lognormal(10, 1, periods)
52
+
53
+ df = pd.DataFrame({
54
+ 'timestamp': timestamps,
55
+ 'open': opens,
56
+ 'high': highs,
57
+ 'low': lows,
58
+ 'close': prices,
59
+ 'volume': volumes
60
+ })
61
+
62
+ df.set_index('timestamp', inplace=True)
63
+ return df
64
+
65
+ except Exception as e:
66
+ logger.error(f"Error loading historical data for {symbol}: {e}")
67
+ return None
68
+
69
+ def run_backtest(self, symbol: str, strategy_params: Optional[Dict[str, Any]] = None,
70
+ start_date: Optional[datetime] = None, end_date: Optional[datetime] = None) -> Dict[str, Any]:
71
+ try:
72
+ log(f"πŸ”„ Starting backtest for {symbol}")
73
+
74
+ df = self.load_historical_data(symbol)
75
+ if df is None or df.empty:
76
+ return {'error': f'No data available for {symbol}'}
77
+
78
+ if start_date:
79
+ df = df[df.index >= start_date]
80
+ if end_date:
81
+ df = df[df.index <= end_date]
82
+
83
+ if len(df) < 100:
84
+ return {'error': f'Insufficient data for {symbol}: {len(df)} candles'}
85
+
86
+ data_engine = DataEngine()
87
+ strategy = ScalpingStrategy(data_engine)
88
+
89
+ if strategy_params:
90
+ for key, value in strategy_params.items():
91
+ if hasattr(strategy, key):
92
+ setattr(strategy, key, value)
93
+
94
+ mock_exchange = MockExchange(self.fee_rate, self.slippage)
95
+
96
+ risk_manager = RiskManager(mock_exchange)
97
+ risk_manager.max_daily_loss = float('inf')
98
+
99
+ trades, equity_curve = self._simulate_trading(
100
+ df, strategy, risk_manager, mock_exchange, symbol
101
+ )
102
+
103
+ metrics = self._calculate_metrics(trades, equity_curve, df)
104
+
105
+ result = {
106
+ 'symbol': symbol,
107
+ 'total_trades': len(trades),
108
+ 'winning_trades': sum(1 for t in trades if t['pnl'] > 0),
109
+ 'losing_trades': sum(1 for t in trades if t['pnl'] < 0),
110
+ 'total_pnl': sum(t['pnl'] for t in trades),
111
+ 'max_drawdown': metrics['max_drawdown'],
112
+ 'win_rate': metrics['win_rate'],
113
+ 'profit_factor': metrics['profit_factor'],
114
+ 'sharpe_ratio': metrics['sharpe_ratio'],
115
+ 'avg_trade_duration': metrics['avg_trade_duration'],
116
+ 'trades': trades[:50],
117
+ 'equity_curve': equity_curve[-100:]
118
+ }
119
+
120
+ self.results[symbol] = result
121
+ log(f"βœ… Backtest completed for {symbol}: {len(trades)} trades, PnL: {result['total_pnl']:.2f}")
122
+
123
+ return result
124
+
125
+ except Exception as e:
126
+ logger.error(f"Error in backtest for {symbol}: {e}")
127
+ return {'error': str(e)}
128
+
129
+ def _simulate_trading(self, df: pd.DataFrame, strategy: ScalpingStrategy,
130
+ risk_manager: RiskManager, exchange: 'MockExchange',
131
+ symbol: str) -> Tuple[List[Dict], List[float]]:
132
+ trades = []
133
+ equity_curve = [self.initial_balance]
134
+ open_position = None
135
+
136
+ for i, (timestamp, row) in enumerate(df.iterrows()):
137
+ current_price = row['close']
138
+
139
+ candle_data = {
140
+ 'timestamp': timestamp.timestamp() * 1000,
141
+ 'open': row['open'],
142
+ 'high': row['high'],
143
+ 'low': row['low'],
144
+ 'close': row['close'],
145
+ 'volume': row['volume']
146
+ }
147
+
148
+ historical_df = df.iloc[:i+1]
149
+ strategy_data_engine = DataEngine()
150
+
151
+ for j in range(max(0, i-200), i+1):
152
+ hist_candle = df.iloc[j]
153
+ hist_data = {
154
+ 'timestamp': df.index[j].timestamp() * 1000,
155
+ 'open': hist_candle['open'],
156
+ 'high': hist_candle['high'],
157
+ 'low': hist_candle['low'],
158
+ 'close': hist_candle['close'],
159
+ 'volume': hist_candle['volume']
160
+ }
161
+ strategy_data_engine.update_candle(symbol, "1", hist_data)
162
+
163
+ strategy.data_engine = strategy_data_engine
164
+
165
+ if open_position:
166
+
167
+ position_age = (timestamp - open_position['entry_time']).seconds / 60
168
+
169
+ exit_reason = None
170
+ if open_position['side'] == 'BUY':
171
+ if current_price >= open_position['tp_price']:
172
+ exit_reason = 'TP'
173
+ elif current_price <= open_position['sl_price']:
174
+ exit_reason = 'SL'
175
+ elif position_age > 15:
176
+ exit_reason = 'TIMEOUT'
177
+ else:
178
+ if current_price <= open_position['tp_price']:
179
+ exit_reason = 'TP'
180
+ elif current_price >= open_position['sl_price']:
181
+ exit_reason = 'SL'
182
+ elif position_age > 15:
183
+ exit_reason = 'TIMEOUT'
184
+
185
+ if exit_reason:
186
+
187
+ pnl = exchange.close_position(open_position, current_price)
188
+ equity_curve.append(equity_curve[-1] + pnl)
189
+
190
+ trade = {
191
+ 'entry_time': open_position['entry_time'],
192
+ 'exit_time': timestamp,
193
+ 'side': open_position['side'],
194
+ 'entry_price': open_position['entry_price'],
195
+ 'exit_price': current_price,
196
+ 'quantity': open_position['quantity'],
197
+ 'pnl': pnl,
198
+ 'reason': exit_reason,
199
+ 'duration_minutes': position_age
200
+ }
201
+ trades.append(trade)
202
+
203
+ open_position = None
204
+
205
+ elif i > 50:
206
+ signal, confidence, price = strategy.generate_signal(symbol)
207
+
208
+ if signal in ['BUY', 'SELL'] and confidence > 0.6:
209
+
210
+ if risk_manager.validate_entry_signal(symbol, signal, confidence):
211
+
212
+ qty = risk_manager.calculate_position_size(symbol, price, signal)
213
+
214
+ if qty > 0:
215
+
216
+ open_position = {
217
+ 'entry_time': timestamp,
218
+ 'side': signal,
219
+ 'entry_price': price,
220
+ 'quantity': qty,
221
+ 'tp_price': price * (1.025 if signal == 'BUY' else 0.975),
222
+ 'sl_price': price * (0.99 if signal == 'BUY' else 1.01)
223
+ }
224
+
225
+ return trades, equity_curve
226
+
227
+ def _calculate_metrics(self, trades: List[Dict], equity_curve: List[float],
228
+ df: pd.DataFrame) -> Dict[str, float]:
229
+ try:
230
+ if not trades:
231
+ return {
232
+ 'max_drawdown': 0.0,
233
+ 'win_rate': 0.0,
234
+ 'profit_factor': 0.0,
235
+ 'sharpe_ratio': 0.0,
236
+ 'avg_trade_duration': 0.0
237
+ }
238
+
239
+ peak = equity_curve[0]
240
+ max_drawdown = 0.0
241
+
242
+ for equity in equity_curve:
243
+ if equity > peak:
244
+ peak = equity
245
+ drawdown = (peak - equity) / peak
246
+ max_drawdown = max(max_drawdown, drawdown)
247
+
248
+ winning_trades = [t for t in trades if t['pnl'] > 0]
249
+ win_rate = len(winning_trades) / len(trades) if trades else 0.0
250
+
251
+ gross_profit = sum(t['pnl'] for t in winning_trades)
252
+ gross_loss = abs(sum(t['pnl'] for t in trades if t['pnl'] < 0))
253
+ profit_factor = gross_profit / gross_loss if gross_loss > 0 else float('inf')
254
+
255
+ returns = np.diff(equity_curve) / equity_curve[:-1]
256
+ if len(returns) > 1 and np.std(returns) > 0:
257
+ sharpe_ratio = np.mean(returns) / np.std(returns) * np.sqrt(365 * 24 * 60)
258
+ else:
259
+ sharpe_ratio = 0.0
260
+
261
+ durations = [t['duration_minutes'] for t in trades]
262
+ avg_trade_duration = np.mean(durations) if durations else 0.0
263
+
264
+ return {
265
+ 'max_drawdown': max_drawdown,
266
+ 'win_rate': win_rate,
267
+ 'profit_factor': profit_factor,
268
+ 'sharpe_ratio': sharpe_ratio,
269
+ 'avg_trade_duration': avg_trade_duration
270
+ }
271
+
272
+ except Exception as e:
273
+ logger.error(f"Error calculating metrics: {e}")
274
+ return {
275
+ 'max_drawdown': 0.0,
276
+ 'win_rate': 0.0,
277
+ 'profit_factor': 0.0,
278
+ 'sharpe_ratio': 0.0,
279
+ 'avg_trade_duration': 0.0
280
+ }
281
+
282
+ def optimize_parameters(self, symbol: str, param_ranges: Dict[str, List[float]]) -> Dict[str, Any]:
283
+ try:
284
+ log(f"🎯 Starting parameter optimization for {symbol}")
285
+
286
+ best_result = None
287
+ best_params = None
288
+ best_score = -float('inf')
289
+
290
+ from itertools import product
291
+ param_names = list(param_ranges.keys())
292
+ param_values = list(param_ranges.values())
293
+
294
+ total_combinations = np.prod([len(v) for v in param_values])
295
+ log(f"Testing {total_combinations} parameter combinations")
296
+
297
+ for i, param_combo in enumerate(product(*param_values)):
298
+ param_dict = dict(zip(param_names, param_combo))
299
+
300
+ result = self.run_backtest(symbol, strategy_params=param_dict)
301
+
302
+ if 'error' not in result:
303
+
304
+ score = result['sharpe_ratio'] - result['max_drawdown'] * 10
305
+
306
+ if score > best_score:
307
+ best_score = score
308
+ best_result = result
309
+ best_params = param_dict
310
+
311
+ if (i + 1) % 10 == 0:
312
+ log(f"Progress: {i + 1}/{total_combinations} combinations tested")
313
+
314
+ if best_result:
315
+ log(f"βœ… Optimization completed. Best params: {best_params}")
316
+ return {
317
+ 'best_parameters': best_params,
318
+ 'best_result': best_result,
319
+ 'optimization_score': best_score
320
+ }
321
+ else:
322
+ return {'error': 'No valid results found during optimization'}
323
+
324
+ except Exception as e:
325
+ logger.error(f"Error in parameter optimization: {e}")
326
+ return {'error': str(e)}
327
+
328
+ def save_results(self, filename: str = "backtest_results.json"):
329
+ try:
330
+ os.makedirs("backtest_results", exist_ok=True)
331
+ filepath = f"backtest_results/{filename}"
332
+
333
+ with open(filepath, 'w') as f:
334
+ json.dump(self.results, f, indent=2, default=str)
335
+
336
+ log(f"πŸ’Ύ Results saved to {filepath}")
337
+
338
+ except Exception as e:
339
+ logger.error(f"Error saving results: {e}")
340
+
341
+ def load_results(self, filename: str = "backtest_results.json") -> Dict[str, Any]:
342
+ try:
343
+ filepath = f"backtest_results/{filename}"
344
+
345
+ if os.path.exists(filepath):
346
+ with open(filepath, 'r') as f:
347
+ self.results = json.load(f)
348
+ log(f"πŸ“‚ Results loaded from {filepath}")
349
+ return self.results
350
+ else:
351
+ return {}
352
+
353
+ except Exception as e:
354
+ logger.error(f"Error loading results: {e}")
355
+ return {}
356
+
357
+ def generate_report(self, symbol: str) -> str:
358
+ try:
359
+ if symbol not in self.results:
360
+ return f"No backtest results found for {symbol}"
361
+
362
+ result = self.results[symbol]
363
+
364
+ report = f
365
+
366
+ for i, trade in enumerate(result['trades'][-5:]):
367
+ report += f"{i+1}. {trade['side']} {trade['quantity']:.3f} @ {trade['entry_price']:.2f} -> {trade['exit_price']:.2f} (PnL: ${trade['pnl']:.2f})\n"
368
+
369
+ return report
370
+
371
+ except Exception as e:
372
+ logger.error(f"Error generating report: {e}")
373
+ return f"Error generating report: {e}"
374
+
375
+ class MockExchange:
376
+
377
+ def __init__(self, fee_rate: float = 0.001, slippage: float = 0.0005):
378
+ self.fee_rate = fee_rate
379
+ self.slippage = slippage
380
+
381
+ def get_balance(self):
382
+ return [{"coin": "USDT", "walletBalance": "10000"}]
383
+
384
+ def get_positions(self):
385
+ return []
386
+
387
+ def calculate_position_size(self, symbol, entry_price, side):
388
+ return 0.01
389
+
390
+ def validate_entry_signal(self, symbol, signal, confidence):
391
+ return True
392
+
393
+ def close_position(self, position, exit_price):
394
+ entry_price = position['entry_price']
395
+ quantity = position['quantity']
396
+ side = position['side']
397
+
398
+ if side == 'BUY':
399
+ exit_price *= (1 - self.slippage)
400
+ else:
401
+ exit_price *= (1 + self.slippage)
402
+
403
+ if side == 'BUY':
404
+ pnl = (exit_price - entry_price) / entry_price * quantity
405
+ else:
406
+ pnl = (entry_price - exit_price) / entry_price * quantity
407
+
408
+ fee = abs(pnl) * self.fee_rate
409
+ pnl -= fee
410
+
411
+ return pnl
config/pairs.yaml ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ pairs:
2
+ - BTCUSDT
3
+ - ETHUSDT
4
+ - SOLUSDT
config/settings.yaml ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ trading:
2
+ leverage: 20
3
+ tp_percent: 0.025
4
+ sl_percent: 0.01
5
+ trailing_tp: true
6
+
7
+ strategy:
8
+ interval: "1"
9
+ rsi_period: 14
10
+ ema_fast: 9
11
+ ema_slow: 21
12
+
13
+ risk:
14
+ risk_per_trade: 0.02
15
+
16
+ telegram:
17
+ enabled: true
core/__pycache__/data_engine.cpython-312.pyc ADDED
Binary file (13.5 kB). View file
 
core/__pycache__/exchange.cpython-312.pyc ADDED
Binary file (8.37 kB). View file
 
core/__pycache__/indicators.cpython-312.pyc ADDED
Binary file (15.6 kB). View file
 
core/__pycache__/risk.cpython-312.pyc ADDED
Binary file (15.6 kB). View file
 
core/__pycache__/strategy.cpython-312.pyc ADDED
Binary file (11.2 kB). View file
 
core/__pycache__/trade_monitor.cpython-312.pyc ADDED
Binary file (12.1 kB). View file
 
core/__pycache__/websockets.cpython-312.pyc ADDED
Binary file (17 kB). View file
 
core/data_engine.py ADDED
@@ -0,0 +1,241 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import pandas as pd
2
+ import numpy as np
3
+ from collections import deque
4
+ import logging
5
+ import time
6
+ import yaml
7
+
8
+ logger = logging.getLogger(__name__)
9
+
10
+ class DataEngine:
11
+ def __init__(self):
12
+ self.settings = yaml.safe_load(open("config/settings.yaml"))
13
+
14
+ self.price_buffers = {}
15
+ self.volume_buffers = {}
16
+
17
+ self.candle_buffers = {}
18
+
19
+ self.indicators_cache = {}
20
+
21
+ self.max_price_buffer = 1000
22
+ self.max_candle_buffer = 200
23
+
24
+ pairs = yaml.safe_load(open("config/pairs.yaml"))["pairs"]
25
+ for pair in pairs:
26
+ self._init_buffers(pair)
27
+
28
+ def _init_buffers(self, symbol):
29
+ self.price_buffers[symbol] = deque(maxlen=self.max_price_buffer)
30
+ self.volume_buffers[symbol] = deque(maxlen=self.max_price_buffer)
31
+
32
+ intervals = ["1", "5", "15"]
33
+ for interval in intervals:
34
+ key = f"{symbol}_{interval}"
35
+ self.candle_buffers[key] = deque(maxlen=self.max_candle_buffer)
36
+ self.indicators_cache[key] = {}
37
+
38
+ def update_price(self, symbol, price, volume=0):
39
+ self.price_buffers[symbol].append(float(price))
40
+ if volume > 0:
41
+ self.volume_buffers[symbol].append(float(volume))
42
+
43
+ def update_candle(self, symbol, interval, candle_data):
44
+ key = f"{symbol}_{interval}"
45
+
46
+ if isinstance(candle_data, dict):
47
+ candle = {
48
+ 'timestamp': int(candle_data.get('timestamp', candle_data.get('start', time.time() * 1000))),
49
+ 'open': float(candle_data['open']),
50
+ 'high': float(candle_data['high']),
51
+ 'low': float(candle_data['low']),
52
+ 'close': float(candle_data['close']),
53
+ 'volume': float(candle_data.get('volume', 0))
54
+ }
55
+ elif isinstance(candle_data, list):
56
+
57
+ candle = {
58
+ 'timestamp': int(candle_data[0]),
59
+ 'open': float(candle_data[1]),
60
+ 'high': float(candle_data[2]),
61
+ 'low': float(candle_data[3]),
62
+ 'close': float(candle_data[4]),
63
+ 'volume': float(candle_data[5])
64
+ }
65
+ else:
66
+ logger.error(f"Invalid candle data format: {candle_data}")
67
+ return
68
+
69
+ self.candle_buffers[key].append(candle)
70
+
71
+ self.update_price(symbol, candle['close'], candle['volume'])
72
+
73
+ self.indicators_cache[key] = {}
74
+
75
+ def get_prices(self, symbol, limit=100):
76
+ return list(self.price_buffers.get(symbol, deque()))[-limit:]
77
+
78
+ def get_candles(self, symbol, interval="1", limit=100):
79
+ key = f"{symbol}_{interval}"
80
+ candles = list(self.candle_buffers.get(key, deque()))[-limit:]
81
+
82
+ if not candles:
83
+ return pd.DataFrame()
84
+
85
+ df = pd.DataFrame(candles)
86
+ df['timestamp'] = pd.to_datetime(df['timestamp'], unit='ms')
87
+ df.set_index('timestamp', inplace=True)
88
+
89
+ return df
90
+
91
+ def calculate_ema(self, symbol, interval="1", period=9):
92
+ key = f"{symbol}_{interval}"
93
+ cache_key = f"ema_{period}"
94
+
95
+ if cache_key in self.indicators_cache[key]:
96
+ return self.indicators_cache[key][cache_key]
97
+
98
+ df = self.get_candles(symbol, interval, limit=period * 2)
99
+ if df.empty or len(df) < period:
100
+ return None
101
+
102
+ ema = df['close'].ewm(span=period, adjust=False).mean()
103
+ self.indicators_cache[key][cache_key] = ema.iloc[-1] if not ema.empty else None
104
+
105
+ return ema.iloc[-1]
106
+
107
+ def calculate_rsi(self, symbol, interval="1", period=14):
108
+ key = f"{symbol}_{interval}"
109
+ cache_key = f"rsi_{period}"
110
+
111
+ if cache_key in self.indicators_cache[key]:
112
+ return self.indicators_cache[key][cache_key]
113
+
114
+ df = self.get_candles(symbol, interval, limit=period * 3)
115
+ if df.empty or len(df) < period + 1:
116
+ return None
117
+
118
+ delta = df['close'].diff()
119
+ gain = (delta.where(delta > 0, 0)).rolling(window=period).mean()
120
+ loss = (-delta.where(delta < 0, 0)).rolling(window=period).mean()
121
+
122
+ rs = gain / loss
123
+ rsi = 100 - (100 / (1 + rs))
124
+
125
+ self.indicators_cache[key][cache_key] = rsi.iloc[-1] if not rsi.empty else None
126
+
127
+ return rsi.iloc[-1]
128
+
129
+ def calculate_adx(self, symbol, interval="1", period=14):
130
+ key = f"{symbol}_{interval}"
131
+ cache_key = f"adx_{period}"
132
+
133
+ if cache_key in self.indicators_cache[key]:
134
+ return self.indicators_cache[key][cache_key]
135
+
136
+ df = self.get_candles(symbol, interval, limit=period * 3)
137
+ if df.empty or len(df) < period + 1:
138
+ return None
139
+
140
+ df['hl'] = df['high'] - df['low']
141
+ df['hc'] = np.abs(df['high'] - df['close'].shift(1))
142
+ df['lc'] = np.abs(df['low'] - df['close'].shift(1))
143
+ df['tr'] = df[['hl', 'hc', 'lc']].max(axis=1)
144
+
145
+ df['dm_plus'] = np.where((df['high'] - df['high'].shift(1)) > (df['low'].shift(1) - df['low']),
146
+ np.maximum(df['high'] - df['high'].shift(1), 0), 0)
147
+ df['dm_minus'] = np.where((df['low'].shift(1) - df['low']) > (df['high'] - df['high'].shift(1)),
148
+ np.maximum(df['low'].shift(1) - df['low'], 0), 0)
149
+
150
+ df['di_plus'] = 100 * (df['dm_plus'].rolling(window=period).mean() / df['tr'].rolling(window=period).mean())
151
+ df['di_minus'] = 100 * (df['dm_minus'].rolling(window=period).mean() / df['tr'].rolling(window=period).mean())
152
+
153
+ df['dx'] = 100 * np.abs(df['di_plus'] - df['di_minus']) / (df['di_plus'] + df['di_minus'])
154
+ adx = df['dx'].rolling(window=period).mean()
155
+
156
+ self.indicators_cache[key][cache_key] = adx.iloc[-1] if not adx.empty else None
157
+
158
+ return adx.iloc[-1]
159
+
160
+ def get_orderbook_imbalance(self, symbol, orderbook_data=None):
161
+ if orderbook_data is None:
162
+
163
+ return 0.0
164
+
165
+ bids = orderbook_data.get('b', [])
166
+ asks = orderbook_data.get('a', [])
167
+
168
+ bid_volume = sum(float(bid[1]) for bid in bids[:10])
169
+ ask_volume = sum(float(ask[1]) for ask in asks[:10])
170
+
171
+ total_volume = bid_volume + ask_volume
172
+ if total_volume == 0:
173
+ return 0.0
174
+
175
+ imbalance = (bid_volume - ask_volume) / total_volume
176
+
177
+ return imbalance
178
+
179
+ def get_spread(self, symbol, orderbook_data=None):
180
+ if orderbook_data is None:
181
+ return 0.0
182
+
183
+ bids = orderbook_data.get('b', [])
184
+ asks = orderbook_data.get('a', [])
185
+
186
+ if not bids or not asks:
187
+ return 0.0
188
+
189
+ best_bid = float(bids[0][0])
190
+ best_ask = float(asks[0][0])
191
+
192
+ spread = (best_ask - best_bid) / best_bid
193
+ return spread
194
+
195
+ def detect_volume_spike(self, symbol, interval="1", threshold=2.0):
196
+ df = self.get_candles(symbol, interval, limit=20)
197
+ if df.empty or len(df) < 5:
198
+ return False
199
+
200
+ current_volume = df['volume'].iloc[-1]
201
+ avg_volume = df['volume'].iloc[:-1].mean()
202
+
203
+ if avg_volume == 0:
204
+ return False
205
+
206
+ return (current_volume / avg_volume) > threshold
207
+
208
+ def get_price_change_rate(self, symbol, periods=5):
209
+ prices = self.get_prices(symbol, limit=periods + 1)
210
+ if len(prices) < periods + 1:
211
+ return 0.0
212
+
213
+ old_price = prices[0]
214
+ new_price = prices[-1]
215
+
216
+ if old_price == 0:
217
+ return 0.0
218
+
219
+ return (new_price - old_price) / old_price
220
+
221
+ def clear_cache(self, symbol=None, interval=None):
222
+ if symbol and interval:
223
+ key = f"{symbol}_{interval}"
224
+ if key in self.indicators_cache:
225
+ self.indicators_cache[key] = {}
226
+ elif symbol:
227
+
228
+ for key in list(self.indicators_cache.keys()):
229
+ if key.startswith(f"{symbol}_"):
230
+ self.indicators_cache[key] = {}
231
+ else:
232
+
233
+ self.indicators_cache = {}
234
+
235
+ def get_buffer_status(self):
236
+ status = {
237
+ 'price_buffers': {symbol: len(buffer) for symbol, buffer in self.price_buffers.items()},
238
+ 'candle_buffers': {key: len(buffer) for key, buffer in self.candle_buffers.items()},
239
+ 'indicators_cache': {key: list(cache.keys()) for key, cache in self.indicators_cache.items()}
240
+ }
241
+ return status
core/exchange.py ADDED
@@ -0,0 +1,186 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from pybit.unified_trading import HTTP
2
+ from dotenv import load_dotenv
3
+ import os
4
+ import yaml
5
+ import time
6
+ import logging
7
+
8
+ load_dotenv()
9
+ logger = logging.getLogger(__name__)
10
+
11
+ class BybitExchange:
12
+ def __init__(self):
13
+ self.settings = yaml.safe_load(open("config/settings.yaml"))
14
+
15
+ API_KEY = os.getenv("BYBIT_API_KEY")
16
+ API_SECRET = os.getenv("BYBIT_API_SECRET")
17
+ TESTNET = os.getenv("BYBIT_TESTNET", "true").lower() == "true"
18
+
19
+ if not API_KEY or not API_SECRET:
20
+ raise Exception("API keys missing in .env")
21
+
22
+ self.session = HTTP(
23
+ api_key=API_KEY,
24
+ api_secret=API_SECRET,
25
+ testnet=TESTNET
26
+ )
27
+
28
+ self.max_retries = 3
29
+ self.retry_delay = 1
30
+
31
+ def _retry_request(self, func, *args, **kwargs):
32
+ for attempt in range(self.max_retries):
33
+ try:
34
+ response = func(*args, **kwargs)
35
+ if "retCode" in response and response["retCode"] == 0:
36
+ return response
37
+ else:
38
+ logger.warning(f"API call failed: {response}")
39
+ if attempt < self.max_retries - 1:
40
+ time.sleep(self.retry_delay * (attempt + 1))
41
+ continue
42
+ raise Exception(f"API call failed after {self.max_retries} attempts: {response}")
43
+ except Exception as e:
44
+ logger.error(f"API request error: {e}")
45
+ if attempt < self.max_retries - 1:
46
+ time.sleep(self.retry_delay * (attempt + 1))
47
+ continue
48
+ raise e
49
+
50
+ def get_balance(self):
51
+ response = self._retry_request(self.session.get_wallet_balance, accountType="UNIFIED")
52
+ return response["result"]["list"][0]["coin"]
53
+
54
+ def get_positions(self, symbol=None):
55
+ params = {"category": "linear"}
56
+ if symbol:
57
+ params["symbol"] = symbol
58
+
59
+ response = self._retry_request(self.session.get_positions, **params)
60
+ return response["result"]["list"]
61
+
62
+ def set_leverage(self, symbol, leverage=None):
63
+ lev = leverage or self.settings["trading"]["leverage"]
64
+ response = self._retry_request(
65
+ self.session.set_leverage,
66
+ category="linear",
67
+ symbol=symbol,
68
+ buyLeverage=str(lev),
69
+ sellLeverage=str(lev)
70
+ )
71
+ return response
72
+
73
+ def market_order(self, symbol, side, qty, reduce_only=False):
74
+ params = {
75
+ "category": "linear",
76
+ "symbol": symbol,
77
+ "side": side.upper(),
78
+ "orderType": "Market",
79
+ "qty": str(qty)
80
+ }
81
+
82
+ if reduce_only:
83
+ params["reduceOnly"] = True
84
+
85
+ response = self._retry_request(self.session.place_order, **params)
86
+ return response["result"]
87
+
88
+ def limit_order(self, symbol, side, qty, price, reduce_only=False):
89
+ params = {
90
+ "category": "linear",
91
+ "symbol": symbol,
92
+ "side": side.upper(),
93
+ "orderType": "Limit",
94
+ "qty": str(qty),
95
+ "price": str(price)
96
+ }
97
+
98
+ if reduce_only:
99
+ params["reduceOnly"] = True
100
+
101
+ response = self._retry_request(self.session.place_order, **params)
102
+ return response["result"]
103
+
104
+ def set_tp_sl(self, symbol, side, entry_price, tp_price, sl_price):
105
+ response = self._retry_request(
106
+ self.session.set_trading_stop,
107
+ category="linear",
108
+ symbol=symbol,
109
+ takeProfit=str(tp_price),
110
+ stopLoss=str(sl_price),
111
+ tpTriggerBy="LastPrice",
112
+ slTriggerBy="LastPrice"
113
+ )
114
+ return response
115
+
116
+ def cancel_order(self, symbol, order_id=None):
117
+ params = {"category": "linear", "symbol": symbol}
118
+ if order_id:
119
+ params["orderId"] = order_id
120
+
121
+ response = self._retry_request(self.session.cancel_order, **params)
122
+ return response["result"]
123
+
124
+ def cancel_all_orders(self, symbol=None):
125
+ params = {"category": "linear"}
126
+ if symbol:
127
+ params["symbol"] = symbol
128
+
129
+ response = self._retry_request(self.session.cancel_all_orders, **params)
130
+ return response["result"]
131
+
132
+ def close_position(self, symbol):
133
+ positions = self.get_positions(symbol)
134
+ if not positions:
135
+ return None
136
+
137
+ position = positions[0]
138
+ size = float(position["size"])
139
+
140
+ if size > 0:
141
+
142
+ return self.market_order(symbol, "Sell", size, reduce_only=True)
143
+ elif size < 0:
144
+
145
+ return self.market_order(symbol, "Buy", abs(size), reduce_only=True)
146
+
147
+ return None
148
+
149
+ def get_active_orders(self, symbol=None):
150
+ params = {"category": "linear"}
151
+ if symbol:
152
+ params["symbol"] = symbol
153
+
154
+ response = self._retry_request(self.session.get_open_orders, **params)
155
+ return response["result"]["list"]
156
+
157
+ def get_kline_data(self, symbol, interval="1", limit=200):
158
+ response = self._retry_request(
159
+ self.session.get_kline,
160
+ category="linear",
161
+ symbol=symbol,
162
+ interval=interval,
163
+ limit=limit
164
+ )
165
+ return response["result"]["list"]
166
+
167
+ def get_orderbook(self, symbol, limit=25):
168
+ response = self._retry_request(
169
+ self.session.get_orderbook,
170
+ category="linear",
171
+ symbol=symbol,
172
+ limit=limit
173
+ )
174
+ return response["result"]
175
+
176
+ def get_ticker(self, symbol):
177
+ response = self._retry_request(
178
+ self.session.get_tickers,
179
+ category="linear",
180
+ symbol=symbol
181
+ )
182
+ return response["result"]["list"][0]
183
+
184
+ def get_server_time(self):
185
+ response = self._retry_request(self.session.get_server_time)
186
+ return response["result"]["timeSecond"]
core/indicators.py ADDED
@@ -0,0 +1,254 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import pandas as pd
2
+ import numpy as np
3
+ from typing import Optional, List, Dict, Any
4
+ import logging
5
+
6
+ logger = logging.getLogger(__name__)
7
+
8
+ class TechnicalIndicators:
9
+ def __init__(self):
10
+ pass
11
+
12
+ @staticmethod
13
+ def sma(data: pd.Series, period: int) -> pd.Series:
14
+ return data.rolling(window=period).mean()
15
+
16
+ @staticmethod
17
+ def ema(data: pd.Series, period: int) -> pd.Series:
18
+ return data.ewm(span=period, adjust=False).mean()
19
+
20
+ @staticmethod
21
+ def rsi(data: pd.Series, period: int = 14) -> pd.Series:
22
+ delta = data.diff()
23
+ gain = (delta.where(delta > 0, 0)).rolling(window=period).mean()
24
+ loss = (-delta.where(delta < 0, 0)).rolling(window=period).mean()
25
+
26
+ rs = gain / loss
27
+ rsi = 100 - (100 / (1 + rs))
28
+
29
+ return rsi
30
+
31
+ @staticmethod
32
+ def macd(data: pd.Series, fast_period: int = 12, slow_period: int = 26, signal_period: int = 9) -> Dict[str, pd.Series]:
33
+ fast_ema = TechnicalIndicators.ema(data, fast_period)
34
+ slow_ema = TechnicalIndicators.ema(data, slow_period)
35
+
36
+ macd_line = fast_ema - slow_ema
37
+ signal_line = TechnicalIndicators.ema(macd_line, signal_period)
38
+ histogram = macd_line - signal_line
39
+
40
+ return {
41
+ 'macd': macd_line,
42
+ 'signal': signal_line,
43
+ 'histogram': histogram
44
+ }
45
+
46
+ @staticmethod
47
+ def bollinger_bands(data: pd.Series, period: int = 20, std_dev: float = 2.0) -> Dict[str, pd.Series]:
48
+ sma = TechnicalIndicators.sma(data, period)
49
+ std = data.rolling(window=period).std()
50
+
51
+ upper_band = sma + (std * std_dev)
52
+ lower_band = sma - (std * std_dev)
53
+
54
+ return {
55
+ 'upper': upper_band,
56
+ 'middle': sma,
57
+ 'lower': lower_band
58
+ }
59
+
60
+ @staticmethod
61
+ def adx(high: pd.Series, low: pd.Series, close: pd.Series, period: int = 14) -> pd.Series:
62
+
63
+ hl = high - low
64
+ hc = np.abs(high - close.shift(1))
65
+ lc = np.abs(low - close.shift(1))
66
+ tr = pd.concat([hl, hc, lc], axis=1).max(axis=1)
67
+
68
+ dm_plus = np.where((high - high.shift(1)) > (low.shift(1) - low),
69
+ np.maximum(high - high.shift(1), 0), 0)
70
+ dm_minus = np.where((low.shift(1) - low) > (high - high.shift(1)),
71
+ np.maximum(low.shift(1) - low), 0)
72
+
73
+ tr_smooth = tr.rolling(window=period).mean()
74
+ dm_plus_smooth = pd.Series(dm_plus).rolling(window=period).mean()
75
+ dm_minus_smooth = pd.Series(dm_minus).rolling(window=period).mean()
76
+
77
+ di_plus = 100 * (dm_plus_smooth / tr_smooth)
78
+ di_minus = 100 * (dm_minus_smooth / tr_smooth)
79
+
80
+ dx = 100 * np.abs(di_plus - di_minus) / (di_plus + di_minus)
81
+ adx = dx.rolling(window=period).mean()
82
+
83
+ return adx
84
+
85
+ @staticmethod
86
+ def stochastic_oscillator(high: pd.Series, low: pd.Series, close: pd.Series,
87
+ k_period: int = 14, d_period: int = 3) -> Dict[str, pd.Series]:
88
+ lowest_low = low.rolling(window=k_period).min()
89
+ highest_high = high.rolling(window=k_period).max()
90
+
91
+ k_percent = 100 * ((close - lowest_low) / (highest_high - lowest_low))
92
+ d_percent = k_percent.rolling(window=d_period).mean()
93
+
94
+ return {
95
+ 'k': k_percent,
96
+ 'd': d_percent
97
+ }
98
+
99
+ @staticmethod
100
+ def williams_r(high: pd.Series, low: pd.Series, close: pd.Series, period: int = 14) -> pd.Series:
101
+ highest_high = high.rolling(window=period).max()
102
+ lowest_low = low.rolling(window=period).min()
103
+
104
+ williams_r = -100 * ((highest_high - close) / (highest_high - lowest_low))
105
+
106
+ return williams_r
107
+
108
+ @staticmethod
109
+ def cci(high: pd.Series, low: pd.Series, close: pd.Series, period: int = 20) -> pd.Series:
110
+ typical_price = (high + low + close) / 3
111
+ sma_tp = TechnicalIndicators.sma(typical_price, period)
112
+ mad = lambda x: np.mean(np.abs(x - x.mean()))
113
+ mean_deviation = typical_price.rolling(window=period).apply(mad, raw=False)
114
+
115
+ cci = (typical_price - sma_tp) / (0.015 * mean_deviation)
116
+
117
+ return cci
118
+
119
+ @staticmethod
120
+ def atr(high: pd.Series, low: pd.Series, close: pd.Series, period: int = 14) -> pd.Series:
121
+ hl = high - low
122
+ hc = np.abs(high - close.shift(1))
123
+ lc = np.abs(low - close.shift(1))
124
+ tr = pd.concat([hl, hc, lc], axis=1).max(axis=1)
125
+
126
+ atr = tr.rolling(window=period).mean()
127
+
128
+ return atr
129
+
130
+ @staticmethod
131
+ def ichimoku_cloud(high: pd.Series, low: pd.Series, conversion_period: int = 9,
132
+ base_period: int = 26, span_b_period: int = 52,
133
+ lagging_period: int = 26) -> Dict[str, pd.Series]:
134
+
135
+ conversion_line = (high.rolling(window=conversion_period).max() +
136
+ low.rolling(window=conversion_period).min()) / 2
137
+
138
+ base_line = (high.rolling(window=base_period).max() +
139
+ low.rolling(window=base_period).min()) / 2
140
+
141
+ leading_span_a = ((conversion_line + base_line) / 2).shift(lagging_period)
142
+
143
+ leading_span_b = ((high.rolling(window=span_b_period).max() +
144
+ low.rolling(window=span_b_period).min()) / 2).shift(lagging_period)
145
+
146
+ lagging_span = close.shift(-lagging_period)
147
+
148
+ return {
149
+ 'conversion_line': conversion_line,
150
+ 'base_line': base_line,
151
+ 'leading_span_a': leading_span_a,
152
+ 'leading_span_b': leading_span_b,
153
+ 'lagging_span': lagging_span
154
+ }
155
+
156
+ @staticmethod
157
+ def fibonacci_retracements(high: pd.Series, low: pd.Series) -> Dict[str, float]:
158
+ max_high = high.max()
159
+ min_low = low.min()
160
+ diff = max_high - min_low
161
+
162
+ levels = {
163
+ '0.0': max_high,
164
+ '0.236': max_high - 0.236 * diff,
165
+ '0.382': max_high - 0.382 * diff,
166
+ '0.5': max_high - 0.5 * diff,
167
+ '0.618': max_high - 0.618 * diff,
168
+ '0.786': max_high - 0.786 * diff,
169
+ '1.0': min_low
170
+ }
171
+
172
+ return levels
173
+
174
+ @staticmethod
175
+ def detect_crossover(fast_series: pd.Series, slow_series: pd.Series) -> Dict[str, bool]:
176
+
177
+ crossed_above = (fast_series.shift(1) <= slow_series.shift(1)) & (fast_series > slow_series)
178
+
179
+ crossed_below = (fast_series.shift(1) >= slow_series.shift(1)) & (fast_series < slow_series)
180
+
181
+ return {
182
+ 'crossed_above': crossed_above.iloc[-1] if not crossed_above.empty else False,
183
+ 'crossed_below': crossed_below.iloc[-1] if not crossed_below.empty else False
184
+ }
185
+
186
+ @staticmethod
187
+ def volume_profile(volume: pd.Series, price: pd.Series, bins: int = 50) -> Dict[str, Any]:
188
+
189
+ price_min, price_max = price.min(), price.max()
190
+ price_bins = np.linspace(price_min, price_max, bins)
191
+
192
+ volume_profile = []
193
+ for i in range(len(price_bins) - 1):
194
+ mask = (price >= price_bins[i]) & (price < price_bins[i + 1])
195
+ bin_volume = volume[mask].sum()
196
+ volume_profile.append({
197
+ 'price_level': (price_bins[i] + price_bins[i + 1]) / 2,
198
+ 'volume': bin_volume
199
+ })
200
+
201
+ poc = max(volume_profile, key=lambda x: x['volume'])['price_level']
202
+
203
+ total_volume = sum(x['volume'] for x in volume_profile)
204
+ sorted_profile = sorted(volume_profile, key=lambda x: x['volume'], reverse=True)
205
+
206
+ cumulative_volume = 0
207
+ value_area_high = None
208
+ value_area_low = None
209
+
210
+ for level in sorted_profile:
211
+ cumulative_volume += level['volume']
212
+ if cumulative_volume >= total_volume * 0.7:
213
+ break
214
+
215
+ in_value_area = sorted([x for x in volume_profile if x['volume'] > 0],
216
+ key=lambda x: x['volume'], reverse=True)[:len([x for x in sorted_profile if cumulative_volume >= total_volume * 0.7])]
217
+
218
+ if in_value_area:
219
+ prices_in_va = [x['price_level'] for x in in_value_area]
220
+ value_area_high = max(prices_in_va)
221
+ value_area_low = min(prices_in_va)
222
+
223
+ return {
224
+ 'volume_profile': volume_profile,
225
+ 'poc': poc,
226
+ 'value_area_high': value_area_high,
227
+ 'value_area_low': value_area_low
228
+ }
229
+
230
+ @staticmethod
231
+ def order_flow_imbalance(orderbook: Dict) -> Dict[str, float]:
232
+ if not orderbook or 'b' not in orderbook or 'a' not in orderbook:
233
+ return {'imbalance': 0.0, 'bid_pressure': 0.0, 'ask_pressure': 0.0}
234
+
235
+ bids = orderbook['b'][:10]
236
+ asks = orderbook['a'][:10]
237
+
238
+ bid_volume = sum(float(bid[1]) for bid in bids)
239
+ ask_volume = sum(float(ask[1]) for ask in asks)
240
+
241
+ total_volume = bid_volume + ask_volume
242
+
243
+ if total_volume == 0:
244
+ return {'imbalance': 0.0, 'bid_pressure': 0.0, 'ask_pressure': 0.0}
245
+
246
+ imbalance = (bid_volume - ask_volume) / total_volume
247
+ bid_pressure = bid_volume / total_volume
248
+ ask_pressure = ask_volume / total_volume
249
+
250
+ return {
251
+ 'imbalance': imbalance,
252
+ 'bid_pressure': bid_pressure,
253
+ 'ask_pressure': ask_pressure
254
+ }
core/risk.py ADDED
@@ -0,0 +1,267 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import logging
2
+ from typing import Dict, List, Optional, Tuple, Any
3
+ import yaml
4
+ import time
5
+ from datetime import datetime, timedelta
6
+
7
+ logger = logging.getLogger(__name__)
8
+
9
+ class RiskManager:
10
+ def __init__(self, exchange_client):
11
+ self.exchange = exchange_client
12
+ self.settings = yaml.safe_load(open("config/settings.yaml"))
13
+ self.leverage = self.settings["trading"]["leverage"]
14
+ self.tp_percent = self.settings["trading"]["tp_percent"]
15
+ self.sl_percent = self.settings["trading"]["sl_percent"]
16
+ self.risk_per_trade = self.settings["risk"]["risk_per_trade"]
17
+ self.max_daily_loss = 100
18
+ self.daily_pnl = 0.0
19
+ self.daily_trades = 0
20
+ self.max_daily_trades = 50
21
+ self.max_open_positions = 1
22
+ self.min_order_size = 0.001
23
+ self.open_positions = {}
24
+ self.emergency_stop = False
25
+ self.last_reset_time = datetime.now()
26
+ self.trade_history = []
27
+ self.win_count = 0
28
+ self.loss_count = 0
29
+
30
+ def calculate_position_size(self, symbol: str, entry_price: float, side: str) -> float:
31
+ try:
32
+ balance_data = self.exchange.get_balance()
33
+ if not balance_data:
34
+ logger.error("Failed to get account balance")
35
+ return 0.0
36
+ usdt_balance = 0.0
37
+ for coin in balance_data:
38
+ if coin.get("coin") == "USDT":
39
+ usdt_balance = float(coin.get("walletBalance", 0))
40
+ break
41
+ if usdt_balance <= 0:
42
+ logger.warning("Insufficient USDT balance")
43
+ return 0.0
44
+ risk_amount = usdt_balance * self.risk_per_trade
45
+ sl_distance = entry_price * self.sl_percent
46
+ position_size = risk_amount / (sl_distance * self.leverage)
47
+ position_size = max(position_size, self.min_order_size)
48
+ if self.daily_pnl < -self.max_daily_loss:
49
+ logger.warning(f"Daily loss limit reached: {self.daily_pnl}")
50
+ return 0.0
51
+ if self.daily_trades >= self.max_daily_trades:
52
+ logger.warning("Max daily trades reached")
53
+ return 0.0
54
+ if symbol in self.open_positions:
55
+ logger.warning(f"Position already open for {symbol}")
56
+ return 0.0
57
+ position_size = self._validate_position_size(symbol, position_size, entry_price)
58
+ logger.info(f"Calculated position size: {position_size:.4f} for {symbol}")
59
+ return position_size
60
+ except Exception as e:
61
+ logger.error(f"Error calculating position size: {e}")
62
+ return 0.0
63
+
64
+ def _validate_position_size(self, symbol: str, size: float, price: float) -> float:
65
+ try:
66
+ min_size = 0.001
67
+ max_size = 100.0
68
+ validated_size = max(min_size, min(size, max_size))
69
+ if symbol.startswith('BTC'):
70
+ validated_size = round(validated_size, 3)
71
+ elif symbol.startswith('ETH'):
72
+ validated_size = round(validated_size, 2)
73
+ else:
74
+ validated_size = round(validated_size, 1)
75
+ return validated_size
76
+ except Exception as e:
77
+ logger.error(f"Error validating position size: {e}")
78
+ return 0.0
79
+
80
+ def validate_entry_signal(self, symbol: str, signal: str, confidence: float) -> bool:
81
+ try:
82
+ if self.emergency_stop:
83
+ logger.warning("Emergency stop activated")
84
+ return False
85
+ min_confidence = 0.6
86
+ if confidence < min_confidence:
87
+ logger.info(f"Signal confidence too low: {confidence}")
88
+ return False
89
+ if symbol in self.open_positions:
90
+ logger.warning(f"Position already exists for {symbol}")
91
+ return False
92
+ if not self._check_market_conditions(symbol):
93
+ return False
94
+ if self._is_high_volatility(symbol):
95
+ logger.warning(f"High volatility detected for {symbol}")
96
+ return False
97
+ return True
98
+ except Exception as e:
99
+ logger.error(f"Error validating entry signal: {e}")
100
+ return False
101
+
102
+ def _check_market_conditions(self, symbol: str) -> bool:
103
+ try:
104
+ ticker = self.exchange.get_ticker(symbol)
105
+ if not ticker:
106
+ return False
107
+ volume_24h = float(ticker.get("volume24h", 0))
108
+ if volume_24h < 100000:
109
+ logger.warning(f"Low volume for {symbol}: {volume_24h}")
110
+ return False
111
+ bid_price = float(ticker.get("bid1Price", 0))
112
+ ask_price = float(ticker.get("ask1Price", 0))
113
+ if bid_price == 0 or ask_price == 0:
114
+ return False
115
+ spread = (ask_price - bid_price) / bid_price
116
+ max_spread = 0.001
117
+ if spread > max_spread:
118
+ logger.warning(f"Spread too wide for {symbol}: {spread}")
119
+ return False
120
+ return True
121
+ except Exception as e:
122
+ logger.error(f"Error checking market conditions: {e}")
123
+ return False
124
+
125
+ def _is_high_volatility(self, symbol: str) -> bool:
126
+ try:
127
+ prices = self.exchange.get_kline_data(symbol, interval="1", limit=10)
128
+ if not prices or len(prices) < 5:
129
+ return True
130
+ high = max(float(candle[2]) for candle in prices)
131
+ low = min(float(candle[3]) for candle in prices)
132
+ current_price = float(prices[-1][4])
133
+ volatility = (high - low) / current_price
134
+ high_vol_threshold = 0.02
135
+ return volatility > high_vol_threshold
136
+ except Exception as e:
137
+ logger.error(f"Error checking volatility: {e}")
138
+ return True
139
+
140
+ def update_position(self, symbol: str, position_data: Dict[str, Any]):
141
+ try:
142
+ self.open_positions[symbol] = {
143
+ 'entry_time': datetime.now(),
144
+ 'entry_price': float(position_data.get('avgPrice', 0)),
145
+ 'size': float(position_data.get('qty', 0)),
146
+ 'side': position_data.get('side', ''),
147
+ 'leverage': self.leverage
148
+ }
149
+ logger.info(f"Position updated for {symbol}: {self.open_positions[symbol]}")
150
+ except Exception as e:
151
+ logger.error(f"Error updating position for {symbol}: {e}")
152
+
153
+ def close_position(self, symbol: str, reason: str = "manual"):
154
+ try:
155
+ if symbol not in self.open_positions:
156
+ logger.warning(f"No position found for {symbol}")
157
+ return False
158
+ position = self.open_positions[symbol]
159
+ exit_price = self.exchange.get_ticker(symbol)
160
+ if exit_price:
161
+ exit_price = float(exit_price.get("lastPrice", 0))
162
+ entry_price = position['entry_price']
163
+ if position['side'] == 'Buy':
164
+ pnl = (exit_price - entry_price) / entry_price * position['size'] * self.leverage
165
+ else:
166
+ pnl = (entry_price - exit_price) / entry_price * position['size'] * self.leverage
167
+ self.daily_pnl += pnl
168
+ if pnl > 0:
169
+ self.win_count += 1
170
+ else:
171
+ self.loss_count += 1
172
+ self._record_trade(symbol, position, exit_price, pnl, reason)
173
+ del self.open_positions[symbol]
174
+ self.daily_trades += 1
175
+ logger.info(f"Position closed for {symbol}, reason: {reason}")
176
+ return True
177
+ except Exception as e:
178
+ logger.error(f"Error closing position for {symbol}: {e}")
179
+ return False
180
+
181
+ def _record_trade(self, symbol: str, position: Dict, exit_price: float, pnl: float, reason: str):
182
+ try:
183
+ trade = {
184
+ 'symbol': symbol,
185
+ 'entry_time': position['entry_time'],
186
+ 'exit_time': datetime.now(),
187
+ 'entry_price': position['entry_price'],
188
+ 'exit_price': exit_price,
189
+ 'size': position['size'],
190
+ 'side': position['side'],
191
+ 'pnl': pnl,
192
+ 'reason': reason,
193
+ 'leverage': position['leverage']
194
+ }
195
+ self.trade_history.append(trade)
196
+ if len(self.trade_history) > 1000:
197
+ self.trade_history = self.trade_history[-1000:]
198
+ except Exception as e:
199
+ logger.error(f"Error recording trade: {e}")
200
+
201
+ def check_tp_sl_hit(self, symbol: str) -> Optional[str]:
202
+ try:
203
+ if symbol not in self.open_positions:
204
+ return None
205
+ position = self.open_positions[symbol]
206
+ current_price = self.exchange.get_ticker(symbol)
207
+ if not current_price:
208
+ return None
209
+ current_price = float(current_price.get("lastPrice", 0))
210
+ entry_price = position['entry_price']
211
+ if position['side'] == 'Buy':
212
+ tp_price = entry_price * (1 + self.tp_percent)
213
+ sl_price = entry_price * (1 - self.sl_percent)
214
+ if current_price >= tp_price:
215
+ return "TP"
216
+ elif current_price <= sl_price:
217
+ return "SL"
218
+ else:
219
+ tp_price = entry_price * (1 - self.tp_percent)
220
+ sl_price = entry_price * (1 + self.sl_percent)
221
+ if current_price <= tp_price:
222
+ return "TP"
223
+ elif current_price >= sl_price:
224
+ return "SL"
225
+ return None
226
+ except Exception as e:
227
+ logger.error(f"Error checking TP/SL for {symbol}: {e}")
228
+ return None
229
+
230
+ def emergency_stop_all(self):
231
+ try:
232
+ self.emergency_stop = True
233
+ for symbol in list(self.open_positions.keys()):
234
+ self.exchange.close_position(symbol)
235
+ self.close_position(symbol, "emergency_stop")
236
+ logger.critical("Emergency stop activated - all positions closed")
237
+ except Exception as e:
238
+ logger.error(f"Error in emergency stop: {e}")
239
+
240
+ def reset_daily_stats(self):
241
+ try:
242
+ now = datetime.now()
243
+ if now.date() > self.last_reset_time.date():
244
+ self.daily_pnl = 0.0
245
+ self.daily_trades = 0
246
+ self.last_reset_time = now
247
+ logger.info("Daily statistics reset")
248
+ except Exception as e:
249
+ logger.error(f"Error resetting daily stats: {e}")
250
+
251
+ def get_risk_status(self) -> Dict[str, Any]:
252
+ try:
253
+ total_trades = self.win_count + self.loss_count
254
+ win_rate = self.win_count / total_trades if total_trades > 0 else 0.0
255
+ status = {
256
+ 'emergency_stop': self.emergency_stop,
257
+ 'open_positions': len(self.open_positions),
258
+ 'daily_pnl': self.daily_pnl,
259
+ 'daily_trades': self.daily_trades,
260
+ 'win_rate': win_rate,
261
+ 'total_trades': total_trades,
262
+ 'positions': list(self.open_positions.keys())
263
+ }
264
+ return status
265
+ except Exception as e:
266
+ logger.error(f"Error getting risk status: {e}")
267
+ return {'error': str(e)}
core/strategy.py ADDED
@@ -0,0 +1,190 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import pandas as pd
2
+ import numpy as np
3
+ import logging
4
+ from typing import Dict, List, Optional, Tuple, Any
5
+ from core.indicators import TechnicalIndicators
6
+ from core.data_engine import DataEngine
7
+ import yaml
8
+
9
+ logger = logging.getLogger(__name__)
10
+
11
+ class ScalpingStrategy:
12
+ def __init__(self, data_engine: DataEngine):
13
+ self.data_engine = data_engine
14
+ self.settings = yaml.safe_load(open("config/settings.yaml"))
15
+ self.ema_fast_period = self.settings["strategy"]["ema_fast"]
16
+ self.ema_slow_period = self.settings["strategy"]["ema_slow"]
17
+ self.rsi_period = self.settings["strategy"]["rsi_period"]
18
+ self.strategy_weights = {
19
+ 'ema_momentum': 0.4,
20
+ 'breakout': 0.35,
21
+ 'pullback': 0.25
22
+ }
23
+ self.min_confidence = 0.6
24
+
25
+ def generate_signal(self, symbol: str, interval: str = "1") -> Tuple[str, float, float]:
26
+ try:
27
+ current_price = self.data_engine.get_prices(symbol, limit=1)
28
+ if not current_price:
29
+ return "NEUTRAL", 0.0, 0.0
30
+ current_price = current_price[-1]
31
+ ema_signal, ema_conf = self._ema_momentum_strategy(symbol, interval)
32
+ breakout_signal, breakout_conf = self._breakout_strategy(symbol, interval)
33
+ pullback_signal, pullback_conf = self._pullback_strategy(symbol, interval)
34
+ buy_signals = []
35
+ sell_signals = []
36
+ if ema_signal == "BUY":
37
+ buy_signals.append(ema_conf * self.strategy_weights['ema_momentum'])
38
+ elif ema_signal == "SELL":
39
+ sell_signals.append(ema_conf * self.strategy_weights['ema_momentum'])
40
+ if breakout_signal == "BUY":
41
+ buy_signals.append(breakout_conf * self.strategy_weights['breakout'])
42
+ elif breakout_signal == "SELL":
43
+ sell_signals.append(breakout_conf * self.strategy_weights['breakout'])
44
+ if pullback_signal == "BUY":
45
+ buy_signals.append(pullback_conf * self.strategy_weights['pullback'])
46
+ elif pullback_signal == "SELL":
47
+ sell_signals.append(pullback_conf * self.strategy_weights['pullback'])
48
+ buy_strength = sum(buy_signals) if buy_signals else 0.0
49
+ sell_strength = sum(sell_signals) if sell_signals else 0.0
50
+ if buy_strength > self.min_confidence and buy_strength > sell_strength:
51
+ final_confidence = min(buy_strength, 1.0)
52
+ return "BUY", final_confidence, current_price
53
+ elif sell_strength > self.min_confidence and sell_strength > buy_strength:
54
+ final_confidence = min(sell_strength, 1.0)
55
+ return "SELL", final_confidence, current_price
56
+ else:
57
+ return "NEUTRAL", 0.0, current_price
58
+ except Exception as e:
59
+ logger.error(f"Error generating signal for {symbol}: {e}")
60
+ return "NEUTRAL", 0.0, 0.0
61
+
62
+ def _ema_momentum_strategy(self, symbol: str, interval: str) -> Tuple[str, float]:
63
+ try:
64
+ df = self.data_engine.get_candles(symbol, interval, limit=50)
65
+ if df.empty or len(df) < self.ema_slow_period + 5:
66
+ return "NEUTRAL", 0.0
67
+ ema_fast = self.data_engine.calculate_ema(symbol, interval, self.ema_fast_period)
68
+ ema_slow = self.data_engine.calculate_ema(symbol, interval, self.ema_slow_period)
69
+ rsi = self.data_engine.calculate_rsi(symbol, interval, self.rsi_period)
70
+ if ema_fast is None or ema_slow is None or rsi is None:
71
+ return "NEUTRAL", 0.0
72
+ ema_fast_prev = df['close'].ewm(span=self.ema_fast_period, adjust=False).mean().iloc[-2]
73
+ ema_slow_prev = df['close'].ewm(span=self.ema_slow_period, adjust=False).mean().iloc[-2]
74
+ crossover_up = ema_fast_prev <= ema_slow_prev and ema_fast > ema_slow
75
+ crossover_down = ema_fast_prev >= ema_slow_prev and ema_fast < ema_slow
76
+ rsi_oversold = rsi < 35
77
+ rsi_overbought = rsi > 65
78
+ orderbook_imbalance = self.data_engine.get_orderbook_imbalance(symbol)
79
+ confidence = 0.0
80
+ signal = "NEUTRAL"
81
+ if crossover_up and rsi_oversold and orderbook_imbalance > 0.1:
82
+ confidence = 0.8
83
+ signal = "BUY"
84
+ elif crossover_down and rsi_overbought and orderbook_imbalance < -0.1:
85
+ confidence = 0.8
86
+ signal = "SELL"
87
+ return signal, confidence
88
+ except Exception as e:
89
+ logger.error(f"EMA momentum strategy error for {symbol}: {e}")
90
+ return "NEUTRAL", 0.0
91
+
92
+ def _breakout_strategy(self, symbol: str, interval: str) -> Tuple[str, float]:
93
+ try:
94
+ df = self.data_engine.get_candles(symbol, interval, limit=20)
95
+ if df.empty or len(df) < 10:
96
+ return "NEUTRAL", 0.0
97
+ volume_spike = self.data_engine.detect_volume_spike(symbol, interval, threshold=1.8)
98
+ price_change_rate = self.data_engine.get_price_change_rate(symbol, periods=3)
99
+ spread = self.data_engine.get_spread(symbol)
100
+ orderbook_imbalance = self.data_engine.get_orderbook_imbalance(symbol)
101
+ recent_high = df['high'].tail(5).max()
102
+ recent_low = df['low'].tail(5).min()
103
+ current_price = df['close'].iloc[-1]
104
+ breakout_up = current_price > recent_high * 1.001
105
+ breakout_down = current_price < recent_low * 0.999
106
+ confidence = 0.0
107
+ signal = "NEUTRAL"
108
+ if breakout_up and volume_spike and price_change_rate > 0.002 and orderbook_imbalance > 0.15:
109
+ confidence = 0.75
110
+ signal = "BUY"
111
+ elif breakout_down and volume_spike and price_change_rate < -0.002 and orderbook_imbalance < -0.15:
112
+ confidence = 0.75
113
+ signal = "SELL"
114
+ return signal, confidence
115
+ except Exception as e:
116
+ logger.error(f"Breakout strategy error for {symbol}: {e}")
117
+ return "NEUTRAL", 0.0
118
+
119
+ def _pullback_strategy(self, symbol: str, interval: str) -> Tuple[str, float]:
120
+ try:
121
+ df = self.data_engine.get_candles(symbol, interval, limit=30)
122
+ if df.empty or len(df) < 20:
123
+ return "NEUTRAL", 0.0
124
+ ema_21 = df['close'].ewm(span=21, adjust=False).mean()
125
+ ema_slope = ema_21.diff().iloc[-1]
126
+ uptrend = ema_slope > 0
127
+ downtrend = ema_slope < 0
128
+ ema_9 = df['close'].ewm(span=9, adjust=False).mean().iloc[-1]
129
+ current_price = df['close'].iloc[-1]
130
+ price_to_ema_ratio = current_price / ema_9
131
+ recent_volume = df['volume'].tail(5).mean()
132
+ previous_volume = df['volume'].tail(10).head(5).mean()
133
+ volume_trend = recent_volume / previous_volume if previous_volume > 0 else 1.0
134
+ pullback_up = uptrend and price_to_ema_ratio < 0.995
135
+ pullback_down = downtrend and price_to_ema_ratio > 1.005
136
+ volume_decrease_on_pullback = volume_trend < 0.8
137
+ volume_increase_on_continuation = volume_trend > 1.2
138
+ confidence = 0.0
139
+ signal = "NEUTRAL"
140
+ if pullback_up and volume_decrease_on_pullback:
141
+ if volume_increase_on_continuation and current_price > ema_9:
142
+ confidence = 0.7
143
+ signal = "BUY"
144
+ elif pullback_down and volume_decrease_on_pullback:
145
+ if volume_increase_on_continuation and current_price < ema_9:
146
+ confidence = 0.7
147
+ signal = "SELL"
148
+ return signal, confidence
149
+ except Exception as e:
150
+ logger.error(f"Pullback strategy error for {symbol}: {e}")
151
+ return "NEUTRAL", 0.0
152
+
153
+ def get_strategy_status(self, symbol: str) -> Dict[str, Any]:
154
+ try:
155
+ status = {
156
+ 'symbol': symbol,
157
+ 'timestamp': pd.Timestamp.now(),
158
+ 'strategies': {}
159
+ }
160
+ ema_signal, ema_conf = self._ema_momentum_strategy(symbol)
161
+ breakout_signal, breakout_conf = self._breakout_strategy(symbol)
162
+ pullback_signal, pullback_conf = self._pullback_strategy(symbol)
163
+ status['strategies'] = {
164
+ 'ema_momentum': {
165
+ 'signal': ema_signal,
166
+ 'confidence': ema_conf
167
+ },
168
+ 'breakout': {
169
+ 'signal': breakout_signal,
170
+ 'confidence': breakout_conf
171
+ },
172
+ 'pullback': {
173
+ 'signal': pullback_signal,
174
+ 'confidence': pullback_conf
175
+ }
176
+ }
177
+ current_price = self.data_engine.get_prices(symbol, limit=1)
178
+ status['current_price'] = current_price[-1] if current_price else None
179
+ ema_fast = self.data_engine.calculate_ema(symbol, "1", self.ema_fast_period)
180
+ ema_slow = self.data_engine.calculate_ema(symbol, "1", self.ema_slow_period)
181
+ rsi = self.data_engine.calculate_rsi(symbol, "1", self.rsi_period)
182
+ status['indicators'] = {
183
+ 'ema_fast': ema_fast,
184
+ 'ema_slow': ema_slow,
185
+ 'rsi': rsi
186
+ }
187
+ return status
188
+ except Exception as e:
189
+ logger.error(f"Error getting strategy status for {symbol}: {e}")
190
+ return {'error': str(e)}
core/trade_monitor.py ADDED
@@ -0,0 +1,232 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import asyncio
2
+ import logging
3
+ import time
4
+ from typing import Dict, List, Optional, Any
5
+ from datetime import datetime, timedelta
6
+ import yaml
7
+
8
+ from core.exchange import BybitExchange
9
+ from core.strategy import ScalpingStrategy
10
+ from core.risk import RiskManager
11
+ from core.data_engine import DataEngine
12
+ from services.logger import log, log_trade, log_error, log_performance
13
+
14
+ logger = logging.getLogger(__name__)
15
+
16
+ class TradeMonitor:
17
+ def __init__(self, exchange: BybitExchange, strategy: ScalpingStrategy,
18
+ risk_manager: RiskManager, data_engine: DataEngine):
19
+ self.exchange = exchange
20
+ self.strategy = strategy
21
+ self.risk_manager = risk_manager
22
+ self.data_engine = data_engine
23
+
24
+ self.settings = yaml.safe_load(open("config/settings.yaml"))
25
+ self.pairs = yaml.safe_load(open("config/pairs.yaml"))["pairs"]
26
+
27
+ self.is_running = False
28
+ self.monitoring_interval = 2
29
+ self.last_signal_check = {}
30
+ self.signal_cooldown = 30
31
+
32
+ self.performance_check_interval = 300
33
+ self.last_performance_check = datetime.now()
34
+
35
+ async def start_monitoring(self):
36
+ self.is_running = True
37
+ log("πŸš€ Starting trade monitoring loop")
38
+
39
+ try:
40
+ while self.is_running:
41
+ await self._monitoring_cycle()
42
+ await asyncio.sleep(self.monitoring_interval)
43
+
44
+ except Exception as e:
45
+ log_error("monitoring_loop", f"Monitoring loop crashed: {e}")
46
+ self.is_running = False
47
+
48
+ def stop_monitoring(self):
49
+ self.is_running = False
50
+ log("πŸ›‘ Trade monitoring stopped")
51
+
52
+ async def _monitoring_cycle(self):
53
+ try:
54
+
55
+ self.risk_manager.reset_daily_stats()
56
+
57
+ await self._check_open_positions()
58
+
59
+ await self._check_signals()
60
+
61
+ await self._periodic_performance_check()
62
+
63
+ self._health_check()
64
+
65
+ except Exception as e:
66
+ log_error("monitoring_cycle", f"Error in monitoring cycle: {e}")
67
+
68
+ async def _check_open_positions(self):
69
+ try:
70
+ positions = self.exchange.get_positions()
71
+
72
+ for position in positions:
73
+ symbol = position.get("symbol")
74
+ if not symbol:
75
+ continue
76
+
77
+ size = float(position.get("size", 0))
78
+
79
+ if abs(size) < 0.001:
80
+ continue
81
+
82
+ exit_reason = self.risk_manager.check_tp_sl_hit(symbol)
83
+
84
+ if exit_reason:
85
+ log(f"🎯 {exit_reason} hit for {symbol}")
86
+
87
+ close_result = self.exchange.close_position(symbol)
88
+
89
+ if close_result:
90
+
91
+ self.risk_manager.close_position(symbol, exit_reason)
92
+
93
+ exit_price = float(close_result.get("avgPrice", 0))
94
+ log_trade(symbol, "CLOSE", abs(size), exit_price,
95
+ reason=exit_reason)
96
+
97
+ self.last_signal_check[symbol] = datetime.now() - timedelta(seconds=self.signal_cooldown)
98
+
99
+ else:
100
+ log_error("position_close", f"Failed to close position for {symbol}")
101
+
102
+ except Exception as e:
103
+ log_error("position_check", f"Error checking positions: {e}")
104
+
105
+ async def _check_signals(self):
106
+ try:
107
+ current_time = datetime.now()
108
+
109
+ for symbol in self.pairs:
110
+
111
+ last_check = self.last_signal_check.get(symbol)
112
+ if last_check and (current_time - last_check).seconds < self.signal_cooldown:
113
+ continue
114
+
115
+ signal, confidence, price = self.strategy.generate_signal(symbol)
116
+
117
+ if signal in ["BUY", "SELL"]:
118
+
119
+ if self.risk_manager.validate_entry_signal(symbol, signal, confidence):
120
+ await self._execute_signal(symbol, signal, confidence, price)
121
+
122
+ self.last_signal_check[symbol] = current_time
123
+
124
+ except Exception as e:
125
+ log_error("signal_check", f"Error checking signals: {e}")
126
+
127
+ async def _execute_signal(self, symbol: str, signal: str, confidence: float, price: float):
128
+ try:
129
+ log(f"πŸ“ˆ Executing {signal} signal for {symbol} at {price} (conf: {confidence:.2f})")
130
+
131
+ qty = self.risk_manager.calculate_position_size(symbol, price, signal)
132
+
133
+ if qty <= 0:
134
+ log(f"❌ Invalid position size for {symbol}: {qty}")
135
+ return
136
+
137
+ self.exchange.set_leverage(symbol)
138
+
139
+ order = self.exchange.market_order(symbol, signal, qty)
140
+
141
+ if order:
142
+ entry_price = float(order.get("avgPrice", price))
143
+
144
+ tp_percent = self.settings["trading"]["tp_percent"]
145
+ sl_percent = self.settings["trading"]["sl_percent"]
146
+
147
+ if signal == "BUY":
148
+ tp_price = entry_price * (1 + tp_percent)
149
+ sl_price = entry_price * (1 - sl_percent)
150
+ else:
151
+ tp_price = entry_price * (1 - tp_percent)
152
+ sl_price = entry_price * (1 + sl_percent)
153
+
154
+ tp_sl_result = self.exchange.set_tp_sl(symbol, signal, entry_price, tp_price, sl_price)
155
+
156
+ if tp_sl_result:
157
+ log(f"βœ… TP/SL set for {symbol}: TP={tp_price:.4f}, SL={sl_price:.4f}")
158
+
159
+ self.risk_manager.update_position(symbol, order)
160
+
161
+ log_trade(symbol, signal, qty, entry_price, "MARKET")
162
+
163
+ else:
164
+ log_error("tp_sl_setup", f"Failed to set TP/SL for {symbol}")
165
+
166
+ self.exchange.close_position(symbol)
167
+
168
+ else:
169
+ log_error("order_execution", f"Failed to execute order for {symbol}")
170
+
171
+ except Exception as e:
172
+ log_error("signal_execution", f"Error executing signal for {symbol}: {e}")
173
+
174
+ async def _periodic_performance_check(self):
175
+ try:
176
+ current_time = datetime.now()
177
+
178
+ if (current_time - self.last_performance_check).seconds >= self.performance_check_interval:
179
+
180
+ risk_status = self.risk_manager.get_risk_status()
181
+
182
+ from services.logger import logger_instance
183
+ trade_stats = logger_instance.get_trade_statistics()
184
+
185
+ performance_data = {
186
+ **risk_status,
187
+ **trade_stats
188
+ }
189
+
190
+ log_performance("ALL", "5min", performance_data)
191
+
192
+ self.last_performance_check = current_time
193
+
194
+ if risk_status.get('daily_pnl', 0) < -self.risk_manager.max_daily_loss:
195
+ log("🚨 Daily loss limit reached - activating emergency stop")
196
+ self.risk_manager.emergency_stop_all()
197
+
198
+ except Exception as e:
199
+ log_error("performance_check", f"Error in performance check: {e}")
200
+
201
+ def _health_check(self):
202
+ try:
203
+
204
+ server_time = self.exchange.get_server_time()
205
+ if not server_time:
206
+ log_error("health_check", "Exchange connection unhealthy")
207
+
208
+ buffer_status = self.data_engine.get_buffer_status()
209
+
210
+ for symbol, buffers in buffer_status.get('price_buffers', {}).items():
211
+ if buffers < 10:
212
+ log(f"⚠️ Low price buffer for {symbol}: {buffers} points")
213
+
214
+ except Exception as e:
215
+ log_error("health_check", f"Health check error: {e}")
216
+
217
+ def get_monitoring_status(self) -> Dict[str, Any]:
218
+ try:
219
+ return {
220
+ 'is_running': self.is_running,
221
+ 'monitoring_interval': self.monitoring_interval,
222
+ 'active_symbols': len(self.pairs),
223
+ 'open_positions': len(self.risk_manager.open_positions),
224
+ 'last_performance_check': self.last_performance_check.isoformat(),
225
+ 'signal_cooldowns': {
226
+ symbol: self.last_signal_check.get(symbol).isoformat()
227
+ for symbol in self.last_signal_check.keys()
228
+ if self.last_signal_check.get(symbol)
229
+ }
230
+ }
231
+ except Exception as e:
232
+ return {'error': str(e)}
core/websockets.py ADDED
@@ -0,0 +1,274 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import asyncio
2
+ import json
3
+ import websockets
4
+ import logging
5
+ from dotenv import load_dotenv
6
+ import os
7
+ import yaml
8
+ import time
9
+ from collections import defaultdict
10
+
11
+ load_dotenv()
12
+ logger = logging.getLogger(__name__)
13
+
14
+ class BybitWebSocket:
15
+ def __init__(self, callback=None):
16
+ self.settings = yaml.safe_load(open("config/settings.yaml"))
17
+ TESTNET = os.getenv("BYBIT_TESTNET", "true").lower() == "true"
18
+
19
+ self.ws_url = "wss://stream-testnet.bybit.com/v5/public/linear" if TESTNET else "wss://stream.bybit.com/v5/public/linear"
20
+ self.private_ws_url = "wss://stream-testnet.bybit.com/v5/private" if TESTNET else "wss://stream.bybit.com/v5/private"
21
+
22
+ self.callback = callback
23
+ self.subscriptions = set()
24
+ self.data_buffers = defaultdict(list)
25
+
26
+ self.websocket = None
27
+ self.private_websocket = None
28
+ self.is_connected = False
29
+ self.is_private_connected = False
30
+ self.reconnect_delay = 1
31
+ self.max_reconnect_delay = 60
32
+ self.heartbeat_interval = 20
33
+
34
+ self.latest_prices = {}
35
+ self.orderbooks = {}
36
+ self.trades = defaultdict(list)
37
+ self.tickers = {}
38
+
39
+ async def connect(self):
40
+ while True:
41
+ try:
42
+ logger.info(f"Connecting to Bybit WebSocket: {self.ws_url}")
43
+ self.websocket = await websockets.connect(self.ws_url)
44
+ self.is_connected = True
45
+ logger.info("WebSocket connected successfully")
46
+
47
+ asyncio.create_task(self._heartbeat())
48
+
49
+ if self.subscriptions:
50
+ await self._resubscribe()
51
+
52
+ await self._message_handler()
53
+
54
+ except Exception as e:
55
+ logger.error(f"WebSocket connection error: {e}")
56
+ self.is_connected = False
57
+ await self._reconnect()
58
+
59
+ async def connect_private(self):
60
+ API_KEY = os.getenv("BYBIT_API_KEY")
61
+ API_SECRET = os.getenv("BYBIT_API_SECRET")
62
+
63
+ if not API_KEY or not API_SECRET:
64
+ logger.warning("Private WebSocket not available - API keys missing")
65
+ return
66
+
67
+ while True:
68
+ try:
69
+ logger.info(f"Connecting to private WebSocket: {self.private_ws_url}")
70
+ self.private_websocket = await websockets.connect(self.private_ws_url)
71
+ self.is_private_connected = True
72
+ logger.info("Private WebSocket connected successfully")
73
+
74
+ await self._authenticate_private()
75
+
76
+ await self._subscribe_private()
77
+
78
+ await self._private_message_handler()
79
+
80
+ except Exception as e:
81
+ logger.error(f"Private WebSocket connection error: {e}")
82
+ self.is_private_connected = False
83
+ await asyncio.sleep(self.reconnect_delay)
84
+ continue
85
+
86
+ async def _authenticate_private(self):
87
+
88
+ pass
89
+
90
+ async def _subscribe_private(self):
91
+
92
+ subscriptions = [
93
+ {"op": "subscribe", "args": ["position.linear"]},
94
+ {"op": "subscribe", "args": ["order.linear"]},
95
+ {"op": "subscribe", "args": ["wallet"]}
96
+ ]
97
+
98
+ for sub in subscriptions:
99
+ await self.private_websocket.send(json.dumps(sub))
100
+ logger.info(f"Subscribed to private channel: {sub}")
101
+
102
+ async def subscribe_ticker(self, symbols):
103
+ if isinstance(symbols, str):
104
+ symbols = [symbols]
105
+
106
+ args = [f"tickers.{symbol}" for symbol in symbols]
107
+ subscription = {"op": "subscribe", "args": args}
108
+
109
+ await self.websocket.send(json.dumps(subscription))
110
+ self.subscriptions.add(("ticker", tuple(symbols)))
111
+ logger.info(f"Subscribed to tickers: {symbols}")
112
+
113
+ async def subscribe_kline(self, symbols, intervals=None):
114
+ if isinstance(symbols, str):
115
+ symbols = [symbols]
116
+ if intervals is None:
117
+ intervals = ["1", "5"]
118
+
119
+ args = []
120
+ for symbol in symbols:
121
+ for interval in intervals:
122
+ args.append(f"kline.{interval}.{symbol}")
123
+
124
+ subscription = {"op": "subscribe", "args": args}
125
+ await self.websocket.send(json.dumps(subscription))
126
+ self.subscriptions.add(("kline", tuple(symbols), tuple(intervals)))
127
+ logger.info(f"Subscribed to klines: {symbols} - {intervals}")
128
+
129
+ async def subscribe_orderbook(self, symbols, depth=25):
130
+ if isinstance(symbols, str):
131
+ symbols = [symbols]
132
+
133
+ args = [f"orderbook.{depth}.{symbol}" for symbol in symbols]
134
+ subscription = {"op": "subscribe", "args": args}
135
+
136
+ await self.websocket.send(json.dumps(subscription))
137
+ self.subscriptions.add(("orderbook", tuple(symbols), depth))
138
+ logger.info(f"Subscribed to orderbook: {symbols} depth={depth}")
139
+
140
+ async def subscribe_trades(self, symbols):
141
+ if isinstance(symbols, str):
142
+ symbols = [symbols]
143
+
144
+ args = [f"publicTrade.{symbol}" for symbol in symbols]
145
+ subscription = {"op": "subscribe", "args": args}
146
+
147
+ await self.websocket.send(json.dumps(subscription))
148
+ self.subscriptions.add(("trades", tuple(symbols)))
149
+ logger.info(f"Subscribed to trades: {symbols}")
150
+
151
+ async def _resubscribe(self):
152
+ for sub in self.subscriptions:
153
+ sub_type = sub[0]
154
+ if sub_type == "ticker":
155
+ await self.subscribe_ticker(list(sub[1]))
156
+ elif sub_type == "kline":
157
+ await self.subscribe_kline(list(sub[1]), list(sub[2]))
158
+ elif sub_type == "orderbook":
159
+ await self.subscribe_orderbook(list(sub[1]), sub[2])
160
+ elif sub_type == "trades":
161
+ await self.subscribe_trades(list(sub[1]))
162
+
163
+ async def _heartbeat(self):
164
+ while self.is_connected:
165
+ try:
166
+ ping_msg = {"op": "ping"}
167
+ await self.websocket.send(json.dumps(ping_msg))
168
+ await asyncio.sleep(self.heartbeat_interval)
169
+ except Exception as e:
170
+ logger.error(f"Heartbeat error: {e}")
171
+ break
172
+
173
+ async def _message_handler(self):
174
+ try:
175
+ async for message in self.websocket:
176
+ try:
177
+ data = json.loads(message)
178
+
179
+ if "topic" in data:
180
+ await self._process_message(data)
181
+ elif data.get("op") == "pong":
182
+
183
+ pass
184
+ elif "success" in data:
185
+ if data["success"]:
186
+ logger.info("Subscription successful")
187
+ else:
188
+ logger.error(f"Subscription failed: {data}")
189
+
190
+ except json.JSONDecodeError as e:
191
+ logger.error(f"Invalid JSON received: {e}")
192
+ except Exception as e:
193
+ logger.error(f"Message processing error: {e}")
194
+
195
+ except websockets.exceptions.ConnectionClosed:
196
+ logger.warning("WebSocket connection closed")
197
+ self.is_connected = False
198
+
199
+ async def _private_message_handler(self):
200
+ try:
201
+ async for message in self.private_websocket:
202
+ try:
203
+ data = json.loads(message)
204
+ await self._process_private_message(data)
205
+ except Exception as e:
206
+ logger.error(f"Private message processing error: {e}")
207
+ except websockets.exceptions.ConnectionClosed:
208
+ logger.warning("Private WebSocket connection closed")
209
+ self.is_private_connected = False
210
+
211
+ async def _process_message(self, data):
212
+ topic = data["topic"]
213
+ payload = data["data"]
214
+
215
+ if topic.startswith("tickers."):
216
+ symbol = topic.split(".")[1]
217
+ self.tickers[symbol] = payload
218
+ self.latest_prices[symbol] = float(payload["lastPrice"])
219
+
220
+ elif topic.startswith("orderbook."):
221
+ symbol = topic.split(".")[2]
222
+ self.orderbooks[symbol] = payload
223
+
224
+ elif topic.startswith("publicTrade."):
225
+ symbol = topic.split(".")[1]
226
+ self.trades[symbol].extend(payload)
227
+
228
+ self.trades[symbol] = self.trades[symbol][-100:]
229
+
230
+ elif topic.startswith("kline."):
231
+ parts = topic.split(".")
232
+ interval = parts[1]
233
+ symbol = parts[2]
234
+
235
+ key = f"{symbol}_{interval}"
236
+ self.data_buffers[key].extend(payload)
237
+
238
+ self.data_buffers[key] = self.data_buffers[key][-200:]
239
+
240
+ if self.callback:
241
+ await self.callback(data)
242
+
243
+ async def _process_private_message(self, data):
244
+
245
+ if self.callback:
246
+ await self.callback(data)
247
+
248
+ async def _reconnect(self):
249
+ self.reconnect_delay = min(self.reconnect_delay * 2, self.max_reconnect_delay)
250
+ logger.info(f"Reconnecting in {self.reconnect_delay} seconds...")
251
+ await asyncio.sleep(self.reconnect_delay)
252
+
253
+ def get_latest_price(self, symbol):
254
+ return self.latest_prices.get(symbol)
255
+
256
+ def get_orderbook(self, symbol):
257
+ return self.orderbooks.get(symbol)
258
+
259
+ def get_recent_trades(self, symbol, limit=10):
260
+ return self.trades.get(symbol, [])[-limit:]
261
+
262
+ def get_kline_buffer(self, symbol, interval="1", limit=100):
263
+ key = f"{symbol}_{interval}"
264
+ return self.data_buffers.get(key, [])[-limit:]
265
+
266
+ async def close(self):
267
+ if self.websocket:
268
+ await self.websocket.close()
269
+ if self.private_websocket:
270
+ await self.private_websocket.close()
271
+
272
+ self.is_connected = False
273
+ self.is_private_connected = False
274
+ logger.info("WebSocket connections closed")
logs/errors.json ADDED
@@ -0,0 +1,272 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ [
2
+ {
3
+ "timestamp": "2026-01-08T08:37:38.988990",
4
+ "type": "position_check",
5
+ "message": "Error checking positions: Missing some parameters that must be filled in, symbol or settleCoin (ErrCode: 10001) (ErrTime: 14:37:38).\nRequest \u2192 GET https://api.bybit.com/v5/position/list: category=linear.",
6
+ "details": {}
7
+ },
8
+ {
9
+ "timestamp": "2026-01-08T08:37:45.564716",
10
+ "type": "position_check",
11
+ "message": "Error checking positions: Missing some parameters that must be filled in, symbol or settleCoin (ErrCode: 10001) (ErrTime: 14:37:45).\nRequest \u2192 GET https://api.bybit.com/v5/position/list: category=linear.",
12
+ "details": {}
13
+ },
14
+ {
15
+ "timestamp": "2026-01-08T08:37:52.709415",
16
+ "type": "position_check",
17
+ "message": "Error checking positions: Missing some parameters that must be filled in, symbol or settleCoin (ErrCode: 10001) (ErrTime: 14:37:52).\nRequest \u2192 GET https://api.bybit.com/v5/position/list: category=linear.",
18
+ "details": {}
19
+ },
20
+ {
21
+ "timestamp": "2026-01-08T08:37:59.344576",
22
+ "type": "position_check",
23
+ "message": "Error checking positions: Missing some parameters that must be filled in, symbol or settleCoin (ErrCode: 10001) (ErrTime: 14:37:59).\nRequest \u2192 GET https://api.bybit.com/v5/position/list: category=linear.",
24
+ "details": {}
25
+ },
26
+ {
27
+ "timestamp": "2026-01-08T08:38:05.892083",
28
+ "type": "position_check",
29
+ "message": "Error checking positions: Missing some parameters that must be filled in, symbol or settleCoin (ErrCode: 10001) (ErrTime: 14:38:05).\nRequest \u2192 GET https://api.bybit.com/v5/position/list: category=linear.",
30
+ "details": {}
31
+ },
32
+ {
33
+ "timestamp": "2026-01-08T08:38:12.476775",
34
+ "type": "position_check",
35
+ "message": "Error checking positions: Missing some parameters that must be filled in, symbol or settleCoin (ErrCode: 10001) (ErrTime: 14:38:12).\nRequest \u2192 GET https://api.bybit.com/v5/position/list: category=linear.",
36
+ "details": {}
37
+ },
38
+ {
39
+ "timestamp": "2026-01-08T08:38:19.571827",
40
+ "type": "position_check",
41
+ "message": "Error checking positions: Missing some parameters that must be filled in, symbol or settleCoin (ErrCode: 10001) (ErrTime: 14:38:19).\nRequest \u2192 GET https://api.bybit.com/v5/position/list: category=linear.",
42
+ "details": {}
43
+ },
44
+ {
45
+ "timestamp": "2026-01-08T08:38:26.173805",
46
+ "type": "position_check",
47
+ "message": "Error checking positions: Missing some parameters that must be filled in, symbol or settleCoin (ErrCode: 10001) (ErrTime: 14:38:26).\nRequest \u2192 GET https://api.bybit.com/v5/position/list: category=linear.",
48
+ "details": {}
49
+ },
50
+ {
51
+ "timestamp": "2026-01-08T08:38:32.720932",
52
+ "type": "position_check",
53
+ "message": "Error checking positions: Missing some parameters that must be filled in, symbol or settleCoin (ErrCode: 10001) (ErrTime: 14:38:32).\nRequest \u2192 GET https://api.bybit.com/v5/position/list: category=linear.",
54
+ "details": {}
55
+ },
56
+ {
57
+ "timestamp": "2026-01-08T08:38:39.330812",
58
+ "type": "position_check",
59
+ "message": "Error checking positions: Missing some parameters that must be filled in, symbol or settleCoin (ErrCode: 10001) (ErrTime: 14:38:39).\nRequest \u2192 GET https://api.bybit.com/v5/position/list: category=linear.",
60
+ "details": {}
61
+ },
62
+ {
63
+ "timestamp": "2026-01-08T08:38:45.991815",
64
+ "type": "position_check",
65
+ "message": "Error checking positions: Missing some parameters that must be filled in, symbol or settleCoin (ErrCode: 10001) (ErrTime: 14:38:45).\nRequest \u2192 GET https://api.bybit.com/v5/position/list: category=linear.",
66
+ "details": {}
67
+ },
68
+ {
69
+ "timestamp": "2026-01-08T08:38:52.621013",
70
+ "type": "position_check",
71
+ "message": "Error checking positions: Missing some parameters that must be filled in, symbol or settleCoin (ErrCode: 10001) (ErrTime: 14:38:52).\nRequest \u2192 GET https://api.bybit.com/v5/position/list: category=linear.",
72
+ "details": {}
73
+ },
74
+ {
75
+ "timestamp": "2026-01-08T08:38:59.185389",
76
+ "type": "position_check",
77
+ "message": "Error checking positions: Missing some parameters that must be filled in, symbol or settleCoin (ErrCode: 10001) (ErrTime: 14:38:59).\nRequest \u2192 GET https://api.bybit.com/v5/position/list: category=linear.",
78
+ "details": {}
79
+ },
80
+ {
81
+ "timestamp": "2026-01-08T08:39:05.774305",
82
+ "type": "position_check",
83
+ "message": "Error checking positions: Missing some parameters that must be filled in, symbol or settleCoin (ErrCode: 10001) (ErrTime: 14:39:05).\nRequest \u2192 GET https://api.bybit.com/v5/position/list: category=linear.",
84
+ "details": {}
85
+ },
86
+ {
87
+ "timestamp": "2026-01-08T08:39:12.350832",
88
+ "type": "position_check",
89
+ "message": "Error checking positions: Missing some parameters that must be filled in, symbol or settleCoin (ErrCode: 10001) (ErrTime: 14:39:12).\nRequest \u2192 GET https://api.bybit.com/v5/position/list: category=linear.",
90
+ "details": {}
91
+ },
92
+ {
93
+ "timestamp": "2026-01-08T08:39:18.855515",
94
+ "type": "position_check",
95
+ "message": "Error checking positions: Missing some parameters that must be filled in, symbol or settleCoin (ErrCode: 10001) (ErrTime: 14:39:18).\nRequest \u2192 GET https://api.bybit.com/v5/position/list: category=linear.",
96
+ "details": {}
97
+ },
98
+ {
99
+ "timestamp": "2026-01-08T08:39:25.602026",
100
+ "type": "position_check",
101
+ "message": "Error checking positions: Missing some parameters that must be filled in, symbol or settleCoin (ErrCode: 10001) (ErrTime: 14:39:25).\nRequest \u2192 GET https://api.bybit.com/v5/position/list: category=linear.",
102
+ "details": {}
103
+ },
104
+ {
105
+ "timestamp": "2026-01-08T08:39:32.308813",
106
+ "type": "position_check",
107
+ "message": "Error checking positions: Missing some parameters that must be filled in, symbol or settleCoin (ErrCode: 10001) (ErrTime: 14:39:32).\nRequest \u2192 GET https://api.bybit.com/v5/position/list: category=linear.",
108
+ "details": {}
109
+ },
110
+ {
111
+ "timestamp": "2026-01-08T08:39:38.808382",
112
+ "type": "position_check",
113
+ "message": "Error checking positions: Missing some parameters that must be filled in, symbol or settleCoin (ErrCode: 10001) (ErrTime: 14:39:38).\nRequest \u2192 GET https://api.bybit.com/v5/position/list: category=linear.",
114
+ "details": {}
115
+ },
116
+ {
117
+ "timestamp": "2026-01-08T08:39:45.490647",
118
+ "type": "position_check",
119
+ "message": "Error checking positions: Missing some parameters that must be filled in, symbol or settleCoin (ErrCode: 10001) (ErrTime: 14:39:45).\nRequest \u2192 GET https://api.bybit.com/v5/position/list: category=linear.",
120
+ "details": {}
121
+ },
122
+ {
123
+ "timestamp": "2026-01-08T08:39:52.341720",
124
+ "type": "position_check",
125
+ "message": "Error checking positions: Missing some parameters that must be filled in, symbol or settleCoin (ErrCode: 10001) (ErrTime: 14:39:52).\nRequest \u2192 GET https://api.bybit.com/v5/position/list: category=linear.",
126
+ "details": {}
127
+ },
128
+ {
129
+ "timestamp": "2026-01-08T08:39:59.324708",
130
+ "type": "position_check",
131
+ "message": "Error checking positions: Missing some parameters that must be filled in, symbol or settleCoin (ErrCode: 10001) (ErrTime: 14:39:59).\nRequest \u2192 GET https://api.bybit.com/v5/position/list: category=linear.",
132
+ "details": {}
133
+ },
134
+ {
135
+ "timestamp": "2026-01-08T08:40:05.833493",
136
+ "type": "position_check",
137
+ "message": "Error checking positions: Missing some parameters that must be filled in, symbol or settleCoin (ErrCode: 10001) (ErrTime: 14:40:05).\nRequest \u2192 GET https://api.bybit.com/v5/position/list: category=linear.",
138
+ "details": {}
139
+ },
140
+ {
141
+ "timestamp": "2026-01-08T08:40:12.406886",
142
+ "type": "position_check",
143
+ "message": "Error checking positions: Missing some parameters that must be filled in, symbol or settleCoin (ErrCode: 10001) (ErrTime: 14:40:12).\nRequest \u2192 GET https://api.bybit.com/v5/position/list: category=linear.",
144
+ "details": {}
145
+ },
146
+ {
147
+ "timestamp": "2026-01-08T08:40:18.962761",
148
+ "type": "position_check",
149
+ "message": "Error checking positions: Missing some parameters that must be filled in, symbol or settleCoin (ErrCode: 10001) (ErrTime: 14:40:18).\nRequest \u2192 GET https://api.bybit.com/v5/position/list: category=linear.",
150
+ "details": {}
151
+ },
152
+ {
153
+ "timestamp": "2026-01-08T08:40:25.469095",
154
+ "type": "position_check",
155
+ "message": "Error checking positions: Missing some parameters that must be filled in, symbol or settleCoin (ErrCode: 10001) (ErrTime: 14:40:25).\nRequest \u2192 GET https://api.bybit.com/v5/position/list: category=linear.",
156
+ "details": {}
157
+ },
158
+ {
159
+ "timestamp": "2026-01-08T09:18:16.855872",
160
+ "type": "position_check",
161
+ "message": "Error checking positions: HTTPSConnectionPool(host='api.bybit.com', port=443): Max retries exceeded with url: /v5/position/list?category=linear (Caused by NameResolutionError(\"<urllib3.connection.HTTPSConnection object at 0x7fa8c7dadbe0>: Failed to resolve 'api.bybit.com' ([Errno -3] Temporary failure in name resolution)\"))",
162
+ "details": {}
163
+ },
164
+ {
165
+ "timestamp": "2026-01-08T09:18:27.774079",
166
+ "type": "position_check",
167
+ "message": "Error checking positions: Unmatched IP, please check your API key's bound IP addresses. (ErrCode: 10010) (ErrTime: 15:18:27).\nRequest \u2192 GET https://api.bybit.com/v5/position/list: category=linear.",
168
+ "details": {}
169
+ },
170
+ {
171
+ "timestamp": "2026-01-08T09:18:34.383041",
172
+ "type": "position_check",
173
+ "message": "Error checking positions: Unmatched IP, please check your API key's bound IP addresses. (ErrCode: 10010) (ErrTime: 15:18:34).\nRequest \u2192 GET https://api.bybit.com/v5/position/list: category=linear.",
174
+ "details": {}
175
+ },
176
+ {
177
+ "timestamp": "2026-01-08T09:18:40.634319",
178
+ "type": "position_check",
179
+ "message": "Error checking positions: Unmatched IP, please check your API key's bound IP addresses. (ErrCode: 10010) (ErrTime: 15:18:40).\nRequest \u2192 GET https://api.bybit.com/v5/position/list: category=linear.",
180
+ "details": {}
181
+ },
182
+ {
183
+ "timestamp": "2026-01-08T09:18:46.921983",
184
+ "type": "position_check",
185
+ "message": "Error checking positions: Unmatched IP, please check your API key's bound IP addresses. (ErrCode: 10010) (ErrTime: 15:18:46).\nRequest \u2192 GET https://api.bybit.com/v5/position/list: category=linear.",
186
+ "details": {}
187
+ },
188
+ {
189
+ "timestamp": "2026-01-08T09:18:53.245499",
190
+ "type": "position_check",
191
+ "message": "Error checking positions: Unmatched IP, please check your API key's bound IP addresses. (ErrCode: 10010) (ErrTime: 15:18:53).\nRequest \u2192 GET https://api.bybit.com/v5/position/list: category=linear.",
192
+ "details": {}
193
+ },
194
+ {
195
+ "timestamp": "2026-01-08T09:18:59.867702",
196
+ "type": "position_check",
197
+ "message": "Error checking positions: Unmatched IP, please check your API key's bound IP addresses. (ErrCode: 10010) (ErrTime: 15:18:59).\nRequest \u2192 GET https://api.bybit.com/v5/position/list: category=linear.",
198
+ "details": {}
199
+ },
200
+ {
201
+ "timestamp": "2026-01-08T09:19:06.148693",
202
+ "type": "position_check",
203
+ "message": "Error checking positions: Unmatched IP, please check your API key's bound IP addresses. (ErrCode: 10010) (ErrTime: 15:19:06).\nRequest \u2192 GET https://api.bybit.com/v5/position/list: category=linear.",
204
+ "details": {}
205
+ },
206
+ {
207
+ "timestamp": "2026-01-08T09:19:12.462576",
208
+ "type": "position_check",
209
+ "message": "Error checking positions: Unmatched IP, please check your API key's bound IP addresses. (ErrCode: 10010) (ErrTime: 15:19:12).\nRequest \u2192 GET https://api.bybit.com/v5/position/list: category=linear.",
210
+ "details": {}
211
+ },
212
+ {
213
+ "timestamp": "2026-01-08T09:19:18.734882",
214
+ "type": "position_check",
215
+ "message": "Error checking positions: Unmatched IP, please check your API key's bound IP addresses. (ErrCode: 10010) (ErrTime: 15:19:18).\nRequest \u2192 GET https://api.bybit.com/v5/position/list: category=linear.",
216
+ "details": {}
217
+ },
218
+ {
219
+ "timestamp": "2026-01-08T09:19:25.030983",
220
+ "type": "position_check",
221
+ "message": "Error checking positions: Unmatched IP, please check your API key's bound IP addresses. (ErrCode: 10010) (ErrTime: 15:19:25).\nRequest \u2192 GET https://api.bybit.com/v5/position/list: category=linear.",
222
+ "details": {}
223
+ },
224
+ {
225
+ "timestamp": "2026-01-08T09:19:31.982889",
226
+ "type": "position_check",
227
+ "message": "Error checking positions: Unmatched IP, please check your API key's bound IP addresses. (ErrCode: 10010) (ErrTime: 15:19:31).\nRequest \u2192 GET https://api.bybit.com/v5/position/list: category=linear.",
228
+ "details": {}
229
+ },
230
+ {
231
+ "timestamp": "2026-01-08T09:19:38.288181",
232
+ "type": "position_check",
233
+ "message": "Error checking positions: Unmatched IP, please check your API key's bound IP addresses. (ErrCode: 10010) (ErrTime: 15:19:38).\nRequest \u2192 GET https://api.bybit.com/v5/position/list: category=linear.",
234
+ "details": {}
235
+ },
236
+ {
237
+ "timestamp": "2026-01-08T09:19:44.958179",
238
+ "type": "position_check",
239
+ "message": "Error checking positions: Unmatched IP, please check your API key's bound IP addresses. (ErrCode: 10010) (ErrTime: 15:19:44).\nRequest \u2192 GET https://api.bybit.com/v5/position/list: category=linear.",
240
+ "details": {}
241
+ },
242
+ {
243
+ "timestamp": "2026-01-08T09:19:51.266450",
244
+ "type": "position_check",
245
+ "message": "Error checking positions: Unmatched IP, please check your API key's bound IP addresses. (ErrCode: 10010) (ErrTime: 15:19:51).\nRequest \u2192 GET https://api.bybit.com/v5/position/list: category=linear.",
246
+ "details": {}
247
+ },
248
+ {
249
+ "timestamp": "2026-01-08T09:19:57.588008",
250
+ "type": "position_check",
251
+ "message": "Error checking positions: Unmatched IP, please check your API key's bound IP addresses. (ErrCode: 10010) (ErrTime: 15:19:57).\nRequest \u2192 GET https://api.bybit.com/v5/position/list: category=linear.",
252
+ "details": {}
253
+ },
254
+ {
255
+ "timestamp": "2026-01-08T09:20:03.853308",
256
+ "type": "position_check",
257
+ "message": "Error checking positions: Unmatched IP, please check your API key's bound IP addresses. (ErrCode: 10010) (ErrTime: 15:20:03).\nRequest \u2192 GET https://api.bybit.com/v5/position/list: category=linear.",
258
+ "details": {}
259
+ },
260
+ {
261
+ "timestamp": "2026-01-08T09:20:10.119147",
262
+ "type": "position_check",
263
+ "message": "Error checking positions: Unmatched IP, please check your API key's bound IP addresses. (ErrCode: 10010) (ErrTime: 15:20:10).\nRequest \u2192 GET https://api.bybit.com/v5/position/list: category=linear.",
264
+ "details": {}
265
+ },
266
+ {
267
+ "timestamp": "2026-01-08T09:20:16.416108",
268
+ "type": "position_check",
269
+ "message": "Error checking positions: Unmatched IP, please check your API key's bound IP addresses. (ErrCode: 10010) (ErrTime: 15:20:16).\nRequest \u2192 GET https://api.bybit.com/v5/position/list: category=linear.",
270
+ "details": {}
271
+ }
272
+ ]
logs/errors.log ADDED
@@ -0,0 +1,241 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ 2026-01-08 08:34:07,556 - ERROR - WEBSOCKET_START: Failed to start WebSocket: 'NoneType' object has no attribute 'send'
2
+ 2026-01-08 08:34:12,589 - ERROR - POSITION_CHECK: Error checking positions: Missing some parameters that must be filled in, symbol or settleCoin (ErrCode: 10001) (ErrTime: 14:34:12).
3
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
4
+ 2026-01-08 08:34:19,229 - ERROR - POSITION_CHECK: Error checking positions: Missing some parameters that must be filled in, symbol or settleCoin (ErrCode: 10001) (ErrTime: 14:34:19).
5
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
6
+ 2026-01-08 08:34:25,791 - ERROR - POSITION_CHECK: Error checking positions: Missing some parameters that must be filled in, symbol or settleCoin (ErrCode: 10001) (ErrTime: 14:34:25).
7
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
8
+ 2026-01-08 08:34:32,336 - ERROR - POSITION_CHECK: Error checking positions: Missing some parameters that must be filled in, symbol or settleCoin (ErrCode: 10001) (ErrTime: 14:34:32).
9
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
10
+ 2026-01-08 08:34:38,925 - ERROR - POSITION_CHECK: Error checking positions: Missing some parameters that must be filled in, symbol or settleCoin (ErrCode: 10001) (ErrTime: 14:34:38).
11
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
12
+ 2026-01-08 08:34:45,531 - ERROR - POSITION_CHECK: Error checking positions: Missing some parameters that must be filled in, symbol or settleCoin (ErrCode: 10001) (ErrTime: 14:34:45).
13
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
14
+ 2026-01-08 08:34:52,116 - ERROR - POSITION_CHECK: Error checking positions: Missing some parameters that must be filled in, symbol or settleCoin (ErrCode: 10001) (ErrTime: 14:34:52).
15
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
16
+ 2026-01-08 08:34:58,727 - ERROR - POSITION_CHECK: Error checking positions: Missing some parameters that must be filled in, symbol or settleCoin (ErrCode: 10001) (ErrTime: 14:34:58).
17
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
18
+ 2026-01-08 08:35:05,343 - ERROR - POSITION_CHECK: Error checking positions: Missing some parameters that must be filled in, symbol or settleCoin (ErrCode: 10001) (ErrTime: 14:35:05).
19
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
20
+ 2026-01-08 08:35:12,672 - ERROR - POSITION_CHECK: Error checking positions: Missing some parameters that must be filled in, symbol or settleCoin (ErrCode: 10001) (ErrTime: 14:35:12).
21
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
22
+ 2026-01-08 08:35:19,332 - ERROR - POSITION_CHECK: Error checking positions: Missing some parameters that must be filled in, symbol or settleCoin (ErrCode: 10001) (ErrTime: 14:35:19).
23
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
24
+ 2026-01-08 08:35:28,860 - ERROR - POSITION_CHECK: Error checking positions: Missing some parameters that must be filled in, symbol or settleCoin (ErrCode: 10001) (ErrTime: 14:35:28).
25
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
26
+ 2026-01-08 08:35:35,409 - ERROR - POSITION_CHECK: Error checking positions: Missing some parameters that must be filled in, symbol or settleCoin (ErrCode: 10001) (ErrTime: 14:35:35).
27
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
28
+ 2026-01-08 08:35:41,937 - ERROR - POSITION_CHECK: Error checking positions: Missing some parameters that must be filled in, symbol or settleCoin (ErrCode: 10001) (ErrTime: 14:35:41).
29
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
30
+ 2026-01-08 08:35:48,456 - ERROR - POSITION_CHECK: Error checking positions: Missing some parameters that must be filled in, symbol or settleCoin (ErrCode: 10001) (ErrTime: 14:35:48).
31
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
32
+ 2026-01-08 08:35:55,276 - ERROR - POSITION_CHECK: Error checking positions: Missing some parameters that must be filled in, symbol or settleCoin (ErrCode: 10001) (ErrTime: 14:35:55).
33
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
34
+ 2026-01-08 08:36:01,846 - ERROR - POSITION_CHECK: Error checking positions: Missing some parameters that must be filled in, symbol or settleCoin (ErrCode: 10001) (ErrTime: 14:36:01).
35
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
36
+ 2026-01-08 08:36:08,368 - ERROR - POSITION_CHECK: Error checking positions: Missing some parameters that must be filled in, symbol or settleCoin (ErrCode: 10001) (ErrTime: 14:36:08).
37
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
38
+ 2026-01-08 08:36:15,048 - ERROR - POSITION_CHECK: Error checking positions: Missing some parameters that must be filled in, symbol or settleCoin (ErrCode: 10001) (ErrTime: 14:36:15).
39
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
40
+ 2026-01-08 08:36:21,919 - ERROR - POSITION_CHECK: Error checking positions: Missing some parameters that must be filled in, symbol or settleCoin (ErrCode: 10001) (ErrTime: 14:36:21).
41
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
42
+ 2026-01-08 08:36:28,439 - ERROR - POSITION_CHECK: Error checking positions: Missing some parameters that must be filled in, symbol or settleCoin (ErrCode: 10001) (ErrTime: 14:36:28).
43
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
44
+ 2026-01-08 08:36:34,976 - ERROR - POSITION_CHECK: Error checking positions: Missing some parameters that must be filled in, symbol or settleCoin (ErrCode: 10001) (ErrTime: 14:36:34).
45
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
46
+ 2026-01-08 08:36:41,540 - ERROR - POSITION_CHECK: Error checking positions: Missing some parameters that must be filled in, symbol or settleCoin (ErrCode: 10001) (ErrTime: 14:36:41).
47
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
48
+ 2026-01-08 08:36:48,068 - ERROR - POSITION_CHECK: Error checking positions: Missing some parameters that must be filled in, symbol or settleCoin (ErrCode: 10001) (ErrTime: 14:36:48).
49
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
50
+ 2026-01-08 08:36:54,593 - ERROR - POSITION_CHECK: Error checking positions: Missing some parameters that must be filled in, symbol or settleCoin (ErrCode: 10001) (ErrTime: 14:36:54).
51
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
52
+ 2026-01-08 08:37:01,148 - ERROR - POSITION_CHECK: Error checking positions: Missing some parameters that must be filled in, symbol or settleCoin (ErrCode: 10001) (ErrTime: 14:37:01).
53
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
54
+ 2026-01-08 08:37:07,681 - ERROR - POSITION_CHECK: Error checking positions: Missing some parameters that must be filled in, symbol or settleCoin (ErrCode: 10001) (ErrTime: 14:37:07).
55
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
56
+ 2026-01-08 08:37:14,180 - ERROR - POSITION_CHECK: Error checking positions: Missing some parameters that must be filled in, symbol or settleCoin (ErrCode: 10001) (ErrTime: 14:37:14).
57
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
58
+ 2026-01-08 08:37:20,706 - ERROR - POSITION_CHECK: Error checking positions: Missing some parameters that must be filled in, symbol or settleCoin (ErrCode: 10001) (ErrTime: 14:37:20).
59
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
60
+ 2026-01-08 08:37:27,277 - ERROR - POSITION_CHECK: Error checking positions: Missing some parameters that must be filled in, symbol or settleCoin (ErrCode: 10001) (ErrTime: 14:37:27).
61
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
62
+ 2026-01-08 08:37:33,795 - ERROR - POSITION_CHECK: Error checking positions: Missing some parameters that must be filled in, symbol or settleCoin (ErrCode: 10001) (ErrTime: 14:37:33).
63
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
64
+ 2026-01-08 08:37:38,993 - ERROR - POSITION_CHECK: Error checking positions: Missing some parameters that must be filled in, symbol or settleCoin (ErrCode: 10001) (ErrTime: 14:37:38).
65
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
66
+ 2026-01-08 08:37:40,377 - ERROR - POSITION_CHECK: Error checking positions: Missing some parameters that must be filled in, symbol or settleCoin (ErrCode: 10001) (ErrTime: 14:37:40).
67
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
68
+ 2026-01-08 08:37:45,565 - ERROR - POSITION_CHECK: Error checking positions: Missing some parameters that must be filled in, symbol or settleCoin (ErrCode: 10001) (ErrTime: 14:37:45).
69
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
70
+ 2026-01-08 08:37:46,986 - ERROR - POSITION_CHECK: Error checking positions: Missing some parameters that must be filled in, symbol or settleCoin (ErrCode: 10001) (ErrTime: 14:37:46).
71
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
72
+ 2026-01-08 08:37:52,709 - ERROR - POSITION_CHECK: Error checking positions: Missing some parameters that must be filled in, symbol or settleCoin (ErrCode: 10001) (ErrTime: 14:37:52).
73
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
74
+ 2026-01-08 08:37:53,526 - ERROR - POSITION_CHECK: Error checking positions: Missing some parameters that must be filled in, symbol or settleCoin (ErrCode: 10001) (ErrTime: 14:37:53).
75
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
76
+ 2026-01-08 08:37:59,349 - ERROR - POSITION_CHECK: Error checking positions: Missing some parameters that must be filled in, symbol or settleCoin (ErrCode: 10001) (ErrTime: 14:37:59).
77
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
78
+ 2026-01-08 08:38:00,095 - ERROR - POSITION_CHECK: Error checking positions: Missing some parameters that must be filled in, symbol or settleCoin (ErrCode: 10001) (ErrTime: 14:38:00).
79
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
80
+ 2026-01-08 08:38:05,892 - ERROR - POSITION_CHECK: Error checking positions: Missing some parameters that must be filled in, symbol or settleCoin (ErrCode: 10001) (ErrTime: 14:38:05).
81
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
82
+ 2026-01-08 08:38:06,687 - ERROR - POSITION_CHECK: Error checking positions: Missing some parameters that must be filled in, symbol or settleCoin (ErrCode: 10001) (ErrTime: 14:38:06).
83
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
84
+ 2026-01-08 08:38:12,478 - ERROR - POSITION_CHECK: Error checking positions: Missing some parameters that must be filled in, symbol or settleCoin (ErrCode: 10001) (ErrTime: 14:38:12).
85
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
86
+ 2026-01-08 08:38:13,349 - ERROR - POSITION_CHECK: Error checking positions: Missing some parameters that must be filled in, symbol or settleCoin (ErrCode: 10001) (ErrTime: 14:38:13).
87
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
88
+ 2026-01-08 08:38:19,573 - ERROR - POSITION_CHECK: Error checking positions: Missing some parameters that must be filled in, symbol or settleCoin (ErrCode: 10001) (ErrTime: 14:38:19).
89
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
90
+ 2026-01-08 08:38:20,395 - ERROR - POSITION_CHECK: Error checking positions: Missing some parameters that must be filled in, symbol or settleCoin (ErrCode: 10001) (ErrTime: 14:38:20).
91
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
92
+ 2026-01-08 08:38:26,178 - ERROR - POSITION_CHECK: Error checking positions: Missing some parameters that must be filled in, symbol or settleCoin (ErrCode: 10001) (ErrTime: 14:38:26).
93
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
94
+ 2026-01-08 08:38:26,976 - ERROR - POSITION_CHECK: Error checking positions: Missing some parameters that must be filled in, symbol or settleCoin (ErrCode: 10001) (ErrTime: 14:38:26).
95
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
96
+ 2026-01-08 08:38:32,722 - ERROR - POSITION_CHECK: Error checking positions: Missing some parameters that must be filled in, symbol or settleCoin (ErrCode: 10001) (ErrTime: 14:38:32).
97
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
98
+ 2026-01-08 08:38:33,526 - ERROR - POSITION_CHECK: Error checking positions: Missing some parameters that must be filled in, symbol or settleCoin (ErrCode: 10001) (ErrTime: 14:38:33).
99
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
100
+ 2026-01-08 08:38:39,332 - ERROR - POSITION_CHECK: Error checking positions: Missing some parameters that must be filled in, symbol or settleCoin (ErrCode: 10001) (ErrTime: 14:38:39).
101
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
102
+ 2026-01-08 08:38:40,099 - ERROR - POSITION_CHECK: Error checking positions: Missing some parameters that must be filled in, symbol or settleCoin (ErrCode: 10001) (ErrTime: 14:38:40).
103
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
104
+ 2026-01-08 08:38:45,994 - ERROR - POSITION_CHECK: Error checking positions: Missing some parameters that must be filled in, symbol or settleCoin (ErrCode: 10001) (ErrTime: 14:38:45).
105
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
106
+ 2026-01-08 08:38:46,691 - ERROR - POSITION_CHECK: Error checking positions: Missing some parameters that must be filled in, symbol or settleCoin (ErrCode: 10001) (ErrTime: 14:38:46).
107
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
108
+ 2026-01-08 08:38:52,626 - ERROR - POSITION_CHECK: Error checking positions: Missing some parameters that must be filled in, symbol or settleCoin (ErrCode: 10001) (ErrTime: 14:38:52).
109
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
110
+ 2026-01-08 08:38:53,552 - ERROR - POSITION_CHECK: Error checking positions: Missing some parameters that must be filled in, symbol or settleCoin (ErrCode: 10001) (ErrTime: 14:38:53).
111
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
112
+ 2026-01-08 08:38:59,186 - ERROR - POSITION_CHECK: Error checking positions: Missing some parameters that must be filled in, symbol or settleCoin (ErrCode: 10001) (ErrTime: 14:38:59).
113
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
114
+ 2026-01-08 08:39:00,123 - ERROR - POSITION_CHECK: Error checking positions: Missing some parameters that must be filled in, symbol or settleCoin (ErrCode: 10001) (ErrTime: 14:39:00).
115
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
116
+ 2026-01-08 08:39:05,847 - ERROR - POSITION_CHECK: Error checking positions: Missing some parameters that must be filled in, symbol or settleCoin (ErrCode: 10001) (ErrTime: 14:39:05).
117
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
118
+ 2026-01-08 08:39:06,742 - ERROR - POSITION_CHECK: Error checking positions: Missing some parameters that must be filled in, symbol or settleCoin (ErrCode: 10001) (ErrTime: 14:39:06).
119
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
120
+ 2026-01-08 08:39:12,351 - ERROR - POSITION_CHECK: Error checking positions: Missing some parameters that must be filled in, symbol or settleCoin (ErrCode: 10001) (ErrTime: 14:39:12).
121
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
122
+ 2026-01-08 08:39:13,238 - ERROR - POSITION_CHECK: Error checking positions: Missing some parameters that must be filled in, symbol or settleCoin (ErrCode: 10001) (ErrTime: 14:39:13).
123
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
124
+ 2026-01-08 08:39:18,856 - ERROR - POSITION_CHECK: Error checking positions: Missing some parameters that must be filled in, symbol or settleCoin (ErrCode: 10001) (ErrTime: 14:39:18).
125
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
126
+ 2026-01-08 08:39:19,812 - ERROR - POSITION_CHECK: Error checking positions: Missing some parameters that must be filled in, symbol or settleCoin (ErrCode: 10001) (ErrTime: 14:39:19).
127
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
128
+ 2026-01-08 08:39:25,602 - ERROR - POSITION_CHECK: Error checking positions: Missing some parameters that must be filled in, symbol or settleCoin (ErrCode: 10001) (ErrTime: 14:39:25).
129
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
130
+ 2026-01-08 08:39:26,333 - ERROR - POSITION_CHECK: Error checking positions: Missing some parameters that must be filled in, symbol or settleCoin (ErrCode: 10001) (ErrTime: 14:39:26).
131
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
132
+ 2026-01-08 08:39:32,309 - ERROR - POSITION_CHECK: Error checking positions: Missing some parameters that must be filled in, symbol or settleCoin (ErrCode: 10001) (ErrTime: 14:39:32).
133
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
134
+ 2026-01-08 08:39:32,992 - ERROR - POSITION_CHECK: Error checking positions: Missing some parameters that must be filled in, symbol or settleCoin (ErrCode: 10001) (ErrTime: 14:39:32).
135
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
136
+ 2026-01-08 08:39:38,808 - ERROR - POSITION_CHECK: Error checking positions: Missing some parameters that must be filled in, symbol or settleCoin (ErrCode: 10001) (ErrTime: 14:39:38).
137
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
138
+ 2026-01-08 08:39:39,878 - ERROR - POSITION_CHECK: Error checking positions: Missing some parameters that must be filled in, symbol or settleCoin (ErrCode: 10001) (ErrTime: 14:39:39).
139
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
140
+ 2026-01-08 08:39:45,492 - ERROR - POSITION_CHECK: Error checking positions: Missing some parameters that must be filled in, symbol or settleCoin (ErrCode: 10001) (ErrTime: 14:39:45).
141
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
142
+ 2026-01-08 08:39:46,402 - ERROR - POSITION_CHECK: Error checking positions: Missing some parameters that must be filled in, symbol or settleCoin (ErrCode: 10001) (ErrTime: 14:39:46).
143
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
144
+ 2026-01-08 08:39:52,342 - ERROR - POSITION_CHECK: Error checking positions: Missing some parameters that must be filled in, symbol or settleCoin (ErrCode: 10001) (ErrTime: 14:39:52).
145
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
146
+ 2026-01-08 08:39:52,896 - ERROR - POSITION_CHECK: Error checking positions: Missing some parameters that must be filled in, symbol or settleCoin (ErrCode: 10001) (ErrTime: 14:39:52).
147
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
148
+ 2026-01-08 08:39:59,328 - ERROR - POSITION_CHECK: Error checking positions: Missing some parameters that must be filled in, symbol or settleCoin (ErrCode: 10001) (ErrTime: 14:39:59).
149
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
150
+ 2026-01-08 08:39:59,702 - ERROR - POSITION_CHECK: Error checking positions: Missing some parameters that must be filled in, symbol or settleCoin (ErrCode: 10001) (ErrTime: 14:39:59).
151
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
152
+ 2026-01-08 08:40:05,835 - ERROR - POSITION_CHECK: Error checking positions: Missing some parameters that must be filled in, symbol or settleCoin (ErrCode: 10001) (ErrTime: 14:40:05).
153
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
154
+ 2026-01-08 08:40:06,262 - ERROR - POSITION_CHECK: Error checking positions: Missing some parameters that must be filled in, symbol or settleCoin (ErrCode: 10001) (ErrTime: 14:40:06).
155
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
156
+ 2026-01-08 08:40:12,407 - ERROR - POSITION_CHECK: Error checking positions: Missing some parameters that must be filled in, symbol or settleCoin (ErrCode: 10001) (ErrTime: 14:40:12).
157
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
158
+ 2026-01-08 08:40:12,801 - ERROR - POSITION_CHECK: Error checking positions: Missing some parameters that must be filled in, symbol or settleCoin (ErrCode: 10001) (ErrTime: 14:40:12).
159
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
160
+ 2026-01-08 08:40:18,963 - ERROR - POSITION_CHECK: Error checking positions: Missing some parameters that must be filled in, symbol or settleCoin (ErrCode: 10001) (ErrTime: 14:40:18).
161
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
162
+ 2026-01-08 08:40:19,325 - ERROR - POSITION_CHECK: Error checking positions: Missing some parameters that must be filled in, symbol or settleCoin (ErrCode: 10001) (ErrTime: 14:40:19).
163
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
164
+ 2026-01-08 08:40:25,470 - ERROR - POSITION_CHECK: Error checking positions: Missing some parameters that must be filled in, symbol or settleCoin (ErrCode: 10001) (ErrTime: 14:40:25).
165
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
166
+ 2026-01-08 08:40:25,835 - ERROR - POSITION_CHECK: Error checking positions: Missing some parameters that must be filled in, symbol or settleCoin (ErrCode: 10001) (ErrTime: 14:40:25).
167
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
168
+ 2026-01-08 09:18:16,857 - ERROR - POSITION_CHECK: Error checking positions: HTTPSConnectionPool(host='api.bybit.com', port=443): Max retries exceeded with url: /v5/position/list?category=linear (Caused by NameResolutionError("<urllib3.connection.HTTPSConnection object at 0x7fa8c7dadbe0>: Failed to resolve 'api.bybit.com' ([Errno -3] Temporary failure in name resolution)"))
169
+ 2026-01-08 09:18:17,152 - ERROR - POSITION_CHECK: Error checking positions: HTTPSConnectionPool(host='api.bybit.com', port=443): Max retries exceeded with url: /v5/position/list?category=linear (Caused by NameResolutionError("<urllib3.connection.HTTPSConnection object at 0x7f87b3572900>: Failed to resolve 'api.bybit.com' ([Errno -3] Temporary failure in name resolution)"))
170
+ 2026-01-08 09:18:27,355 - ERROR - POSITION_CHECK: Error checking positions: Unmatched IP, please check your API key's bound IP addresses. (ErrCode: 10010) (ErrTime: 15:18:27).
171
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
172
+ 2026-01-08 09:18:27,775 - ERROR - POSITION_CHECK: Error checking positions: Unmatched IP, please check your API key's bound IP addresses. (ErrCode: 10010) (ErrTime: 15:18:27).
173
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
174
+ 2026-01-08 09:18:33,629 - ERROR - POSITION_CHECK: Error checking positions: Unmatched IP, please check your API key's bound IP addresses. (ErrCode: 10010) (ErrTime: 15:18:33).
175
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
176
+ 2026-01-08 09:18:34,384 - ERROR - POSITION_CHECK: Error checking positions: Unmatched IP, please check your API key's bound IP addresses. (ErrCode: 10010) (ErrTime: 15:18:34).
177
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
178
+ 2026-01-08 09:18:39,888 - ERROR - POSITION_CHECK: Error checking positions: Unmatched IP, please check your API key's bound IP addresses. (ErrCode: 10010) (ErrTime: 15:18:39).
179
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
180
+ 2026-01-08 09:18:40,635 - ERROR - POSITION_CHECK: Error checking positions: Unmatched IP, please check your API key's bound IP addresses. (ErrCode: 10010) (ErrTime: 15:18:40).
181
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
182
+ 2026-01-08 09:18:46,160 - ERROR - POSITION_CHECK: Error checking positions: Unmatched IP, please check your API key's bound IP addresses. (ErrCode: 10010) (ErrTime: 15:18:46).
183
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
184
+ 2026-01-08 09:18:46,923 - ERROR - POSITION_CHECK: Error checking positions: Unmatched IP, please check your API key's bound IP addresses. (ErrCode: 10010) (ErrTime: 15:18:46).
185
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
186
+ 2026-01-08 09:18:52,447 - ERROR - POSITION_CHECK: Error checking positions: Unmatched IP, please check your API key's bound IP addresses. (ErrCode: 10010) (ErrTime: 15:18:52).
187
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
188
+ 2026-01-08 09:18:53,247 - ERROR - POSITION_CHECK: Error checking positions: Unmatched IP, please check your API key's bound IP addresses. (ErrCode: 10010) (ErrTime: 15:18:53).
189
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
190
+ 2026-01-08 09:18:58,713 - ERROR - POSITION_CHECK: Error checking positions: Unmatched IP, please check your API key's bound IP addresses. (ErrCode: 10010) (ErrTime: 15:18:58).
191
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
192
+ 2026-01-08 09:18:59,869 - ERROR - POSITION_CHECK: Error checking positions: Unmatched IP, please check your API key's bound IP addresses. (ErrCode: 10010) (ErrTime: 15:18:59).
193
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
194
+ 2026-01-08 09:19:04,983 - ERROR - POSITION_CHECK: Error checking positions: Unmatched IP, please check your API key's bound IP addresses. (ErrCode: 10010) (ErrTime: 15:19:04).
195
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
196
+ 2026-01-08 09:19:06,149 - ERROR - POSITION_CHECK: Error checking positions: Unmatched IP, please check your API key's bound IP addresses. (ErrCode: 10010) (ErrTime: 15:19:06).
197
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
198
+ 2026-01-08 09:19:11,307 - ERROR - POSITION_CHECK: Error checking positions: Unmatched IP, please check your API key's bound IP addresses. (ErrCode: 10010) (ErrTime: 15:19:11).
199
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
200
+ 2026-01-08 09:19:12,464 - ERROR - POSITION_CHECK: Error checking positions: Unmatched IP, please check your API key's bound IP addresses. (ErrCode: 10010) (ErrTime: 15:19:12).
201
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
202
+ 2026-01-08 09:19:17,567 - ERROR - POSITION_CHECK: Error checking positions: Unmatched IP, please check your API key's bound IP addresses. (ErrCode: 10010) (ErrTime: 15:19:17).
203
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
204
+ 2026-01-08 09:19:18,735 - ERROR - POSITION_CHECK: Error checking positions: Unmatched IP, please check your API key's bound IP addresses. (ErrCode: 10010) (ErrTime: 15:19:18).
205
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
206
+ 2026-01-08 09:19:23,898 - ERROR - POSITION_CHECK: Error checking positions: Unmatched IP, please check your API key's bound IP addresses. (ErrCode: 10010) (ErrTime: 15:19:23).
207
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
208
+ 2026-01-08 09:19:25,033 - ERROR - POSITION_CHECK: Error checking positions: Unmatched IP, please check your API key's bound IP addresses. (ErrCode: 10010) (ErrTime: 15:19:25).
209
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
210
+ 2026-01-08 09:19:30,217 - ERROR - POSITION_CHECK: Error checking positions: Unmatched IP, please check your API key's bound IP addresses. (ErrCode: 10010) (ErrTime: 15:19:30).
211
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
212
+ 2026-01-08 09:19:31,983 - ERROR - POSITION_CHECK: Error checking positions: Unmatched IP, please check your API key's bound IP addresses. (ErrCode: 10010) (ErrTime: 15:19:31).
213
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
214
+ 2026-01-08 09:19:36,549 - ERROR - POSITION_CHECK: Error checking positions: Unmatched IP, please check your API key's bound IP addresses. (ErrCode: 10010) (ErrTime: 15:19:36).
215
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
216
+ 2026-01-08 09:19:38,289 - ERROR - POSITION_CHECK: Error checking positions: Unmatched IP, please check your API key's bound IP addresses. (ErrCode: 10010) (ErrTime: 15:19:38).
217
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
218
+ 2026-01-08 09:19:42,883 - ERROR - POSITION_CHECK: Error checking positions: Unmatched IP, please check your API key's bound IP addresses. (ErrCode: 10010) (ErrTime: 15:19:42).
219
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
220
+ 2026-01-08 09:19:44,959 - ERROR - POSITION_CHECK: Error checking positions: Unmatched IP, please check your API key's bound IP addresses. (ErrCode: 10010) (ErrTime: 15:19:44).
221
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
222
+ 2026-01-08 09:19:49,179 - ERROR - POSITION_CHECK: Error checking positions: Unmatched IP, please check your API key's bound IP addresses. (ErrCode: 10010) (ErrTime: 15:19:49).
223
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
224
+ 2026-01-08 09:19:51,268 - ERROR - POSITION_CHECK: Error checking positions: Unmatched IP, please check your API key's bound IP addresses. (ErrCode: 10010) (ErrTime: 15:19:51).
225
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
226
+ 2026-01-08 09:19:56,099 - ERROR - POSITION_CHECK: Error checking positions: Unmatched IP, please check your API key's bound IP addresses. (ErrCode: 10010) (ErrTime: 15:19:56).
227
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
228
+ 2026-01-08 09:19:57,589 - ERROR - POSITION_CHECK: Error checking positions: Unmatched IP, please check your API key's bound IP addresses. (ErrCode: 10010) (ErrTime: 15:19:57).
229
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
230
+ 2026-01-08 09:20:02,381 - ERROR - POSITION_CHECK: Error checking positions: Unmatched IP, please check your API key's bound IP addresses. (ErrCode: 10010) (ErrTime: 15:20:02).
231
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
232
+ 2026-01-08 09:20:03,854 - ERROR - POSITION_CHECK: Error checking positions: Unmatched IP, please check your API key's bound IP addresses. (ErrCode: 10010) (ErrTime: 15:20:03).
233
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
234
+ 2026-01-08 09:20:08,654 - ERROR - POSITION_CHECK: Error checking positions: Unmatched IP, please check your API key's bound IP addresses. (ErrCode: 10010) (ErrTime: 15:20:08).
235
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
236
+ 2026-01-08 09:20:10,120 - ERROR - POSITION_CHECK: Error checking positions: Unmatched IP, please check your API key's bound IP addresses. (ErrCode: 10010) (ErrTime: 15:20:10).
237
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
238
+ 2026-01-08 09:20:15,315 - ERROR - POSITION_CHECK: Error checking positions: Unmatched IP, please check your API key's bound IP addresses. (ErrCode: 10010) (ErrTime: 15:20:15).
239
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
240
+ 2026-01-08 09:20:16,417 - ERROR - POSITION_CHECK: Error checking positions: Unmatched IP, please check your API key's bound IP addresses. (ErrCode: 10010) (ErrTime: 15:20:16).
241
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
logs/performance.jsonl ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ {"timestamp": "2026-01-08T08:39:06.743107", "symbol": "ALL", "period": "5min", "metrics": {"emergency_stop": false, "open_positions": 0, "daily_pnl": 0.0, "daily_trades": 0, "win_rate": 0.0, "total_trades": 0, "positions": [], "total_pnl": 0.0}}
2
+ {"timestamp": "2026-01-08T09:18:16.924852", "symbol": "ALL", "period": "5min", "metrics": {"emergency_stop": false, "open_positions": 0, "daily_pnl": 0.0, "daily_trades": 0, "win_rate": 0.0, "total_trades": 0, "positions": [], "total_pnl": 0.0}}
3
+ {"timestamp": "2026-01-08T09:18:17.152621", "symbol": "ALL", "period": "5min", "metrics": {"emergency_stop": false, "open_positions": 0, "daily_pnl": 0.0, "daily_trades": 0, "win_rate": 0.0, "total_trades": 0, "positions": [], "total_pnl": 0.0}}
logs/scalper.log ADDED
@@ -0,0 +1,512 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ 2026-01-08 08:34:03,664 - scalper - INFO - log:205 - πŸš€ Starting Bybit Scalping Bot v1.0.0
2
+ 2026-01-08 08:34:03,664 - scalper - INFO - log:205 - πŸ“Š Trading pairs: BTCUSDT, ETHUSDT, SOLUSDT
3
+ 2026-01-08 08:34:03,664 - scalper - INFO - log:205 - βš™οΈ Leverage: 20x
4
+ 2026-01-08 08:34:03,665 - scalper - INFO - log:205 - 🎯 Take Profit: 2.5%
5
+ 2026-01-08 08:34:03,665 - scalper - INFO - log:205 - πŸ›‘οΈ Stop Loss: 1.0%
6
+ 2026-01-08 08:34:05,536 - scalper - INFO - log:205 - βœ… Exchange client initialized
7
+ 2026-01-08 08:34:05,542 - scalper - INFO - log:205 - βœ… Data engine initialized
8
+ 2026-01-08 08:34:05,547 - scalper - INFO - log:205 - βœ… Trading strategy initialized
9
+ 2026-01-08 08:34:05,550 - scalper - INFO - log:205 - βœ… Risk manager initialized
10
+ 2026-01-08 08:34:05,553 - scalper - INFO - log:205 - βœ… Trade monitor initialized
11
+ 2026-01-08 08:34:05,554 - scalper - INFO - log:205 - βœ… WebSocket client initialized
12
+ 2026-01-08 08:34:07,556 - scalper - ERROR - log_error:125 - WEBSOCKET_START: Failed to start WebSocket: 'NoneType' object has no attribute 'send'
13
+ 2026-01-08 08:34:07,556 - scalper - INFO - log:205 - ▢️ Bot is now active and monitoring markets
14
+ 2026-01-08 08:34:07,556 - scalper - INFO - log:205 - πŸš€ Starting trade monitoring loop
15
+ 2026-01-08 08:34:12,214 - scalper - INFO - log:205 - πŸ›‘ Shutdown signal received
16
+ 2026-01-08 08:34:12,589 - scalper - ERROR - log_error:125 - POSITION_CHECK: Error checking positions: Missing some parameters that must be filled in, symbol or settleCoin (ErrCode: 10001) (ErrTime: 14:34:12).
17
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
18
+ 2026-01-08 08:34:12,972 - scalper - INFO - log:205 - ⚠️ Low price buffer for BTCUSDT: 0 points
19
+ 2026-01-08 08:34:12,973 - scalper - INFO - log:205 - ⚠️ Low price buffer for ETHUSDT: 0 points
20
+ 2026-01-08 08:34:12,973 - scalper - INFO - log:205 - ⚠️ Low price buffer for SOLUSDT: 0 points
21
+ 2026-01-08 08:34:19,229 - scalper - ERROR - log_error:125 - POSITION_CHECK: Error checking positions: Missing some parameters that must be filled in, symbol or settleCoin (ErrCode: 10001) (ErrTime: 14:34:19).
22
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
23
+ 2026-01-08 08:34:19,633 - scalper - INFO - log:205 - ⚠️ Low price buffer for BTCUSDT: 0 points
24
+ 2026-01-08 08:34:19,633 - scalper - INFO - log:205 - ⚠️ Low price buffer for ETHUSDT: 0 points
25
+ 2026-01-08 08:34:19,633 - scalper - INFO - log:205 - ⚠️ Low price buffer for SOLUSDT: 0 points
26
+ 2026-01-08 08:34:25,791 - scalper - ERROR - log_error:125 - POSITION_CHECK: Error checking positions: Missing some parameters that must be filled in, symbol or settleCoin (ErrCode: 10001) (ErrTime: 14:34:25).
27
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
28
+ 2026-01-08 08:34:26,166 - scalper - INFO - log:205 - ⚠️ Low price buffer for BTCUSDT: 0 points
29
+ 2026-01-08 08:34:26,168 - scalper - INFO - log:205 - ⚠️ Low price buffer for ETHUSDT: 0 points
30
+ 2026-01-08 08:34:26,169 - scalper - INFO - log:205 - ⚠️ Low price buffer for SOLUSDT: 0 points
31
+ 2026-01-08 08:34:32,336 - scalper - ERROR - log_error:125 - POSITION_CHECK: Error checking positions: Missing some parameters that must be filled in, symbol or settleCoin (ErrCode: 10001) (ErrTime: 14:34:32).
32
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
33
+ 2026-01-08 08:34:32,720 - scalper - INFO - log:205 - ⚠️ Low price buffer for BTCUSDT: 0 points
34
+ 2026-01-08 08:34:32,721 - scalper - INFO - log:205 - ⚠️ Low price buffer for ETHUSDT: 0 points
35
+ 2026-01-08 08:34:32,721 - scalper - INFO - log:205 - ⚠️ Low price buffer for SOLUSDT: 0 points
36
+ 2026-01-08 08:34:38,925 - scalper - ERROR - log_error:125 - POSITION_CHECK: Error checking positions: Missing some parameters that must be filled in, symbol or settleCoin (ErrCode: 10001) (ErrTime: 14:34:38).
37
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
38
+ 2026-01-08 08:34:39,304 - scalper - INFO - log:205 - ⚠️ Low price buffer for BTCUSDT: 0 points
39
+ 2026-01-08 08:34:39,304 - scalper - INFO - log:205 - ⚠️ Low price buffer for ETHUSDT: 0 points
40
+ 2026-01-08 08:34:39,305 - scalper - INFO - log:205 - ⚠️ Low price buffer for SOLUSDT: 0 points
41
+ 2026-01-08 08:34:45,531 - scalper - ERROR - log_error:125 - POSITION_CHECK: Error checking positions: Missing some parameters that must be filled in, symbol or settleCoin (ErrCode: 10001) (ErrTime: 14:34:45).
42
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
43
+ 2026-01-08 08:34:45,939 - scalper - INFO - log:205 - ⚠️ Low price buffer for BTCUSDT: 0 points
44
+ 2026-01-08 08:34:45,942 - scalper - INFO - log:205 - ⚠️ Low price buffer for ETHUSDT: 0 points
45
+ 2026-01-08 08:34:45,944 - scalper - INFO - log:205 - ⚠️ Low price buffer for SOLUSDT: 0 points
46
+ 2026-01-08 08:34:52,116 - scalper - ERROR - log_error:125 - POSITION_CHECK: Error checking positions: Missing some parameters that must be filled in, symbol or settleCoin (ErrCode: 10001) (ErrTime: 14:34:52).
47
+ Request οΏ½οΏ½ GET https://api.bybit.com/v5/position/list: category=linear.
48
+ 2026-01-08 08:34:52,509 - scalper - INFO - log:205 - ⚠️ Low price buffer for BTCUSDT: 0 points
49
+ 2026-01-08 08:34:52,510 - scalper - INFO - log:205 - ⚠️ Low price buffer for ETHUSDT: 0 points
50
+ 2026-01-08 08:34:52,510 - scalper - INFO - log:205 - ⚠️ Low price buffer for SOLUSDT: 0 points
51
+ 2026-01-08 08:34:58,727 - scalper - ERROR - log_error:125 - POSITION_CHECK: Error checking positions: Missing some parameters that must be filled in, symbol or settleCoin (ErrCode: 10001) (ErrTime: 14:34:58).
52
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
53
+ 2026-01-08 08:34:59,145 - scalper - INFO - log:205 - ⚠️ Low price buffer for BTCUSDT: 0 points
54
+ 2026-01-08 08:34:59,146 - scalper - INFO - log:205 - ⚠️ Low price buffer for ETHUSDT: 0 points
55
+ 2026-01-08 08:34:59,146 - scalper - INFO - log:205 - ⚠️ Low price buffer for SOLUSDT: 0 points
56
+ 2026-01-08 08:35:05,343 - scalper - ERROR - log_error:125 - POSITION_CHECK: Error checking positions: Missing some parameters that must be filled in, symbol or settleCoin (ErrCode: 10001) (ErrTime: 14:35:05).
57
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
58
+ 2026-01-08 08:35:06,035 - scalper - INFO - log:205 - ⚠️ Low price buffer for BTCUSDT: 0 points
59
+ 2026-01-08 08:35:06,037 - scalper - INFO - log:205 - ⚠️ Low price buffer for ETHUSDT: 0 points
60
+ 2026-01-08 08:35:06,038 - scalper - INFO - log:205 - ⚠️ Low price buffer for SOLUSDT: 0 points
61
+ 2026-01-08 08:35:12,672 - scalper - ERROR - log_error:125 - POSITION_CHECK: Error checking positions: Missing some parameters that must be filled in, symbol or settleCoin (ErrCode: 10001) (ErrTime: 14:35:12).
62
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
63
+ 2026-01-08 08:35:13,089 - scalper - INFO - log:205 - ⚠️ Low price buffer for BTCUSDT: 0 points
64
+ 2026-01-08 08:35:13,089 - scalper - INFO - log:205 - ⚠️ Low price buffer for ETHUSDT: 0 points
65
+ 2026-01-08 08:35:13,090 - scalper - INFO - log:205 - ⚠️ Low price buffer for SOLUSDT: 0 points
66
+ 2026-01-08 08:35:19,332 - scalper - ERROR - log_error:125 - POSITION_CHECK: Error checking positions: Missing some parameters that must be filled in, symbol or settleCoin (ErrCode: 10001) (ErrTime: 14:35:19).
67
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
68
+ 2026-01-08 08:35:19,743 - scalper - INFO - log:205 - ⚠️ Low price buffer for BTCUSDT: 0 points
69
+ 2026-01-08 08:35:19,743 - scalper - INFO - log:205 - ⚠️ Low price buffer for ETHUSDT: 0 points
70
+ 2026-01-08 08:35:19,744 - scalper - INFO - log:205 - ⚠️ Low price buffer for SOLUSDT: 0 points
71
+ 2026-01-08 08:35:28,860 - scalper - ERROR - log_error:125 - POSITION_CHECK: Error checking positions: Missing some parameters that must be filled in, symbol or settleCoin (ErrCode: 10001) (ErrTime: 14:35:28).
72
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
73
+ 2026-01-08 08:35:29,262 - scalper - INFO - log:205 - ⚠️ Low price buffer for BTCUSDT: 0 points
74
+ 2026-01-08 08:35:29,262 - scalper - INFO - log:205 - ⚠️ Low price buffer for ETHUSDT: 0 points
75
+ 2026-01-08 08:35:29,262 - scalper - INFO - log:205 - ⚠️ Low price buffer for SOLUSDT: 0 points
76
+ 2026-01-08 08:35:35,409 - scalper - ERROR - log_error:125 - POSITION_CHECK: Error checking positions: Missing some parameters that must be filled in, symbol or settleCoin (ErrCode: 10001) (ErrTime: 14:35:35).
77
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
78
+ 2026-01-08 08:35:35,769 - scalper - INFO - log:205 - ⚠️ Low price buffer for BTCUSDT: 0 points
79
+ 2026-01-08 08:35:35,770 - scalper - INFO - log:205 - ⚠️ Low price buffer for ETHUSDT: 0 points
80
+ 2026-01-08 08:35:35,770 - scalper - INFO - log:205 - ⚠️ Low price buffer for SOLUSDT: 0 points
81
+ 2026-01-08 08:35:41,937 - scalper - ERROR - log_error:125 - POSITION_CHECK: Error checking positions: Missing some parameters that must be filled in, symbol or settleCoin (ErrCode: 10001) (ErrTime: 14:35:41).
82
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
83
+ 2026-01-08 08:35:42,304 - scalper - INFO - log:205 - ⚠️ Low price buffer for BTCUSDT: 0 points
84
+ 2026-01-08 08:35:42,304 - scalper - INFO - log:205 - ⚠️ Low price buffer for ETHUSDT: 0 points
85
+ 2026-01-08 08:35:42,304 - scalper - INFO - log:205 - ⚠️ Low price buffer for SOLUSDT: 0 points
86
+ 2026-01-08 08:35:48,456 - scalper - ERROR - log_error:125 - POSITION_CHECK: Error checking positions: Missing some parameters that must be filled in, symbol or settleCoin (ErrCode: 10001) (ErrTime: 14:35:48).
87
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
88
+ 2026-01-08 08:35:49,140 - scalper - INFO - log:205 - ⚠️ Low price buffer for BTCUSDT: 0 points
89
+ 2026-01-08 08:35:49,140 - scalper - INFO - log:205 - ⚠️ Low price buffer for ETHUSDT: 0 points
90
+ 2026-01-08 08:35:49,140 - scalper - INFO - log:205 - ⚠️ Low price buffer for SOLUSDT: 0 points
91
+ 2026-01-08 08:35:55,276 - scalper - ERROR - log_error:125 - POSITION_CHECK: Error checking positions: Missing some parameters that must be filled in, symbol or settleCoin (ErrCode: 10001) (ErrTime: 14:35:55).
92
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
93
+ 2026-01-08 08:35:55,667 - scalper - INFO - log:205 - ⚠️ Low price buffer for BTCUSDT: 0 points
94
+ 2026-01-08 08:35:55,667 - scalper - INFO - log:205 - ⚠️ Low price buffer for ETHUSDT: 0 points
95
+ 2026-01-08 08:35:55,667 - scalper - INFO - log:205 - ⚠️ Low price buffer for SOLUSDT: 0 points
96
+ 2026-01-08 08:36:01,846 - scalper - ERROR - log_error:125 - POSITION_CHECK: Error checking positions: Missing some parameters that must be filled in, symbol or settleCoin (ErrCode: 10001) (ErrTime: 14:36:01).
97
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
98
+ 2026-01-08 08:36:02,251 - scalper - INFO - log:205 - ⚠️ Low price buffer for BTCUSDT: 0 points
99
+ 2026-01-08 08:36:02,252 - scalper - INFO - log:205 - ⚠️ Low price buffer for ETHUSDT: 0 points
100
+ 2026-01-08 08:36:02,252 - scalper - INFO - log:205 - ⚠️ Low price buffer for SOLUSDT: 0 points
101
+ 2026-01-08 08:36:08,368 - scalper - ERROR - log_error:125 - POSITION_CHECK: Error checking positions: Missing some parameters that must be filled in, symbol or settleCoin (ErrCode: 10001) (ErrTime: 14:36:08).
102
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
103
+ 2026-01-08 08:36:08,763 - scalper - INFO - log:205 - ⚠️ Low price buffer for BTCUSDT: 0 points
104
+ 2026-01-08 08:36:08,763 - scalper - INFO - log:205 - ⚠️ Low price buffer for ETHUSDT: 0 points
105
+ 2026-01-08 08:36:08,763 - scalper - INFO - log:205 - ⚠️ Low price buffer for SOLUSDT: 0 points
106
+ 2026-01-08 08:36:15,048 - scalper - ERROR - log_error:125 - POSITION_CHECK: Error checking positions: Missing some parameters that must be filled in, symbol or settleCoin (ErrCode: 10001) (ErrTime: 14:36:15).
107
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
108
+ 2026-01-08 08:36:15,426 - scalper - INFO - log:205 - ⚠️ Low price buffer for BTCUSDT: 0 points
109
+ 2026-01-08 08:36:15,427 - scalper - INFO - log:205 - ⚠️ Low price buffer for ETHUSDT: 0 points
110
+ 2026-01-08 08:36:15,427 - scalper - INFO - log:205 - ⚠️ Low price buffer for SOLUSDT: 0 points
111
+ 2026-01-08 08:36:21,919 - scalper - ERROR - log_error:125 - POSITION_CHECK: Error checking positions: Missing some parameters that must be filled in, symbol or settleCoin (ErrCode: 10001) (ErrTime: 14:36:21).
112
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
113
+ 2026-01-08 08:36:22,283 - scalper - INFO - log:205 - ⚠️ Low price buffer for BTCUSDT: 0 points
114
+ 2026-01-08 08:36:22,283 - scalper - INFO - log:205 - ⚠️ Low price buffer for ETHUSDT: 0 points
115
+ 2026-01-08 08:36:22,283 - scalper - INFO - log:205 - ⚠️ Low price buffer for SOLUSDT: 0 points
116
+ 2026-01-08 08:36:28,439 - scalper - ERROR - log_error:125 - POSITION_CHECK: Error checking positions: Missing some parameters that must be filled in, symbol or settleCoin (ErrCode: 10001) (ErrTime: 14:36:28).
117
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
118
+ 2026-01-08 08:36:28,820 - scalper - INFO - log:205 - ⚠️ Low price buffer for BTCUSDT: 0 points
119
+ 2026-01-08 08:36:28,820 - scalper - INFO - log:205 - ⚠️ Low price buffer for ETHUSDT: 0 points
120
+ 2026-01-08 08:36:28,820 - scalper - INFO - log:205 - ⚠️ Low price buffer for SOLUSDT: 0 points
121
+ 2026-01-08 08:36:34,976 - scalper - ERROR - log_error:125 - POSITION_CHECK: Error checking positions: Missing some parameters that must be filled in, symbol or settleCoin (ErrCode: 10001) (ErrTime: 14:36:34).
122
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
123
+ 2026-01-08 08:36:35,344 - scalper - INFO - log:205 - ⚠️ Low price buffer for BTCUSDT: 0 points
124
+ 2026-01-08 08:36:35,344 - scalper - INFO - log:205 - ⚠️ Low price buffer for ETHUSDT: 0 points
125
+ 2026-01-08 08:36:35,344 - scalper - INFO - log:205 - ⚠️ Low price buffer for SOLUSDT: 0 points
126
+ 2026-01-08 08:36:41,540 - scalper - ERROR - log_error:125 - POSITION_CHECK: Error checking positions: Missing some parameters that must be filled in, symbol or settleCoin (ErrCode: 10001) (ErrTime: 14:36:41).
127
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
128
+ 2026-01-08 08:36:41,923 - scalper - INFO - log:205 - ⚠️ Low price buffer for BTCUSDT: 0 points
129
+ 2026-01-08 08:36:41,924 - scalper - INFO - log:205 - ⚠️ Low price buffer for ETHUSDT: 0 points
130
+ 2026-01-08 08:36:41,924 - scalper - INFO - log:205 - ⚠️ Low price buffer for SOLUSDT: 0 points
131
+ 2026-01-08 08:36:48,068 - scalper - ERROR - log_error:125 - POSITION_CHECK: Error checking positions: Missing some parameters that must be filled in, symbol or settleCoin (ErrCode: 10001) (ErrTime: 14:36:48).
132
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
133
+ 2026-01-08 08:36:48,446 - scalper - INFO - log:205 - ⚠️ Low price buffer for BTCUSDT: 0 points
134
+ 2026-01-08 08:36:48,446 - scalper - INFO - log:205 - ⚠️ Low price buffer for ETHUSDT: 0 points
135
+ 2026-01-08 08:36:48,446 - scalper - INFO - log:205 - ⚠️ Low price buffer for SOLUSDT: 0 points
136
+ 2026-01-08 08:36:54,593 - scalper - ERROR - log_error:125 - POSITION_CHECK: Error checking positions: Missing some parameters that must be filled in, symbol or settleCoin (ErrCode: 10001) (ErrTime: 14:36:54).
137
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
138
+ 2026-01-08 08:36:54,964 - scalper - INFO - log:205 - ⚠️ Low price buffer for BTCUSDT: 0 points
139
+ 2026-01-08 08:36:54,965 - scalper - INFO - log:205 - ⚠️ Low price buffer for ETHUSDT: 0 points
140
+ 2026-01-08 08:36:54,965 - scalper - INFO - log:205 - ⚠️ Low price buffer for SOLUSDT: 0 points
141
+ 2026-01-08 08:37:01,148 - scalper - ERROR - log_error:125 - POSITION_CHECK: Error checking positions: Missing some parameters that must be filled in, symbol or settleCoin (ErrCode: 10001) (ErrTime: 14:37:01).
142
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
143
+ 2026-01-08 08:37:01,533 - scalper - INFO - log:205 - ⚠️ Low price buffer for BTCUSDT: 0 points
144
+ 2026-01-08 08:37:01,534 - scalper - INFO - log:205 - ⚠️ Low price buffer for ETHUSDT: 0 points
145
+ 2026-01-08 08:37:01,534 - scalper - INFO - log:205 - ⚠️ Low price buffer for SOLUSDT: 0 points
146
+ 2026-01-08 08:37:07,681 - scalper - ERROR - log_error:125 - POSITION_CHECK: Error checking positions: Missing some parameters that must be filled in, symbol or settleCoin (ErrCode: 10001) (ErrTime: 14:37:07).
147
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
148
+ 2026-01-08 08:37:08,058 - scalper - INFO - log:205 - ⚠️ Low price buffer for BTCUSDT: 0 points
149
+ 2026-01-08 08:37:08,059 - scalper - INFO - log:205 - ⚠️ Low price buffer for ETHUSDT: 0 points
150
+ 2026-01-08 08:37:08,059 - scalper - INFO - log:205 - ⚠️ Low price buffer for SOLUSDT: 0 points
151
+ 2026-01-08 08:37:14,180 - scalper - ERROR - log_error:125 - POSITION_CHECK: Error checking positions: Missing some parameters that must be filled in, symbol or settleCoin (ErrCode: 10001) (ErrTime: 14:37:14).
152
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
153
+ 2026-01-08 08:37:14,563 - scalper - INFO - log:205 - ⚠️ Low price buffer for BTCUSDT: 0 points
154
+ 2026-01-08 08:37:14,563 - scalper - INFO - log:205 - ⚠️ Low price buffer for ETHUSDT: 0 points
155
+ 2026-01-08 08:37:14,563 - scalper - INFO - log:205 - ⚠️ Low price buffer for SOLUSDT: 0 points
156
+ 2026-01-08 08:37:20,706 - scalper - ERROR - log_error:125 - POSITION_CHECK: Error checking positions: Missing some parameters that must be filled in, symbol or settleCoin (ErrCode: 10001) (ErrTime: 14:37:20).
157
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
158
+ 2026-01-08 08:37:21,084 - scalper - INFO - log:205 - ⚠️ Low price buffer for BTCUSDT: 0 points
159
+ 2026-01-08 08:37:21,084 - scalper - INFO - log:205 - ⚠️ Low price buffer for ETHUSDT: 0 points
160
+ 2026-01-08 08:37:21,084 - scalper - INFO - log:205 - ⚠️ Low price buffer for SOLUSDT: 0 points
161
+ 2026-01-08 08:37:27,277 - scalper - ERROR - log_error:125 - POSITION_CHECK: Error checking positions: Missing some parameters that must be filled in, symbol or settleCoin (ErrCode: 10001) (ErrTime: 14:37:27).
162
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
163
+ 2026-01-08 08:37:27,643 - scalper - INFO - log:205 - ⚠️ Low price buffer for BTCUSDT: 0 points
164
+ 2026-01-08 08:37:27,644 - scalper - INFO - log:205 - ⚠️ Low price buffer for ETHUSDT: 0 points
165
+ 2026-01-08 08:37:27,644 - scalper - INFO - log:205 - ⚠️ Low price buffer for SOLUSDT: 0 points
166
+ 2026-01-08 08:37:31,042 - scalper - INFO - log:205 - πŸš€ Starting Bybit Scalping Bot v1.0.0
167
+ 2026-01-08 08:37:31,043 - scalper - INFO - log:205 - πŸ“Š Trading pairs: BTCUSDT, ETHUSDT, SOLUSDT
168
+ 2026-01-08 08:37:31,043 - scalper - INFO - log:205 - βš™οΈ Leverage: 20x
169
+ 2026-01-08 08:37:31,043 - scalper - INFO - log:205 - 🎯 Take Profit: 2.5%
170
+ 2026-01-08 08:37:31,043 - scalper - INFO - log:205 - πŸ›‘οΈ Stop Loss: 1.0%
171
+ 2026-01-08 08:37:32,181 - scalper - INFO - log:205 - βœ… Exchange client initialized
172
+ 2026-01-08 08:37:32,187 - scalper - INFO - log:205 - βœ… Data engine initialized
173
+ 2026-01-08 08:37:32,191 - scalper - INFO - log:205 - βœ… Trading strategy initialized
174
+ 2026-01-08 08:37:32,194 - scalper - INFO - log:205 - βœ… Risk manager initialized
175
+ 2026-01-08 08:37:32,196 - scalper - INFO - log:205 - βœ… Trade monitor initialized
176
+ 2026-01-08 08:37:32,199 - scalper - INFO - log:205 - βœ… WebSocket client initialized
177
+ 2026-01-08 08:37:33,795 - scalper - ERROR - log_error:125 - POSITION_CHECK: Error checking positions: Missing some parameters that must be filled in, symbol or settleCoin (ErrCode: 10001) (ErrTime: 14:37:33).
178
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
179
+ 2026-01-08 08:37:34,168 - scalper - INFO - log:205 - ⚠️ Low price buffer for BTCUSDT: 0 points
180
+ 2026-01-08 08:37:34,168 - scalper - INFO - log:205 - ⚠️ Low price buffer for ETHUSDT: 0 points
181
+ 2026-01-08 08:37:34,168 - scalper - INFO - log:205 - ⚠️ Low price buffer for SOLUSDT: 0 points
182
+ 2026-01-08 08:37:34,201 - scalper - INFO - log:205 - βœ… WebSocket subscriptions active
183
+ 2026-01-08 08:37:34,201 - scalper - INFO - log:205 - ▢️ Bot is now active and monitoring markets
184
+ 2026-01-08 08:37:34,202 - scalper - INFO - log:205 - πŸš€ Starting trade monitoring loop
185
+ 2026-01-08 08:37:38,993 - scalper - ERROR - log_error:125 - POSITION_CHECK: Error checking positions: Missing some parameters that must be filled in, symbol or settleCoin (ErrCode: 10001) (ErrTime: 14:37:38).
186
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
187
+ 2026-01-08 08:37:39,367 - scalper - INFO - log:205 - ⚠️ Low price buffer for BTCUSDT: 0 points
188
+ 2026-01-08 08:37:39,367 - scalper - INFO - log:205 - ⚠️ Low price buffer for ETHUSDT: 0 points
189
+ 2026-01-08 08:37:39,367 - scalper - INFO - log:205 - ⚠️ Low price buffer for SOLUSDT: 0 points
190
+ 2026-01-08 08:37:40,377 - scalper - ERROR - log_error:125 - POSITION_CHECK: Error checking positions: Missing some parameters that must be filled in, symbol or settleCoin (ErrCode: 10001) (ErrTime: 14:37:40).
191
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
192
+ 2026-01-08 08:37:40,747 - scalper - INFO - log:205 - ⚠️ Low price buffer for BTCUSDT: 0 points
193
+ 2026-01-08 08:37:40,748 - scalper - INFO - log:205 - ⚠️ Low price buffer for ETHUSDT: 0 points
194
+ 2026-01-08 08:37:40,748 - scalper - INFO - log:205 - ⚠️ Low price buffer for SOLUSDT: 0 points
195
+ 2026-01-08 08:37:44,764 - scalper - INFO - log:205 - πŸ›‘ Shutdown signal received
196
+ 2026-01-08 08:37:45,565 - scalper - ERROR - log_error:125 - POSITION_CHECK: Error checking positions: Missing some parameters that must be filled in, symbol or settleCoin (ErrCode: 10001) (ErrTime: 14:37:45).
197
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
198
+ 2026-01-08 08:37:46,986 - scalper - ERROR - log_error:125 - POSITION_CHECK: Error checking positions: Missing some parameters that must be filled in, symbol or settleCoin (ErrCode: 10001) (ErrTime: 14:37:46).
199
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
200
+ 2026-01-08 08:37:47,355 - scalper - INFO - log:205 - ⚠️ Low price buffer for BTCUSDT: 0 points
201
+ 2026-01-08 08:37:47,355 - scalper - INFO - log:205 - ⚠️ Low price buffer for ETHUSDT: 0 points
202
+ 2026-01-08 08:37:47,356 - scalper - INFO - log:205 - ⚠️ Low price buffer for SOLUSDT: 0 points
203
+ 2026-01-08 08:37:52,709 - scalper - ERROR - log_error:125 - POSITION_CHECK: Error checking positions: Missing some parameters that must be filled in, symbol or settleCoin (ErrCode: 10001) (ErrTime: 14:37:52).
204
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
205
+ 2026-01-08 08:37:53,526 - scalper - ERROR - log_error:125 - POSITION_CHECK: Error checking positions: Missing some parameters that must be filled in, symbol or settleCoin (ErrCode: 10001) (ErrTime: 14:37:53).
206
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
207
+ 2026-01-08 08:37:53,939 - scalper - INFO - log:205 - ⚠️ Low price buffer for BTCUSDT: 0 points
208
+ 2026-01-08 08:37:53,940 - scalper - INFO - log:205 - ⚠️ Low price buffer for ETHUSDT: 0 points
209
+ 2026-01-08 08:37:53,941 - scalper - INFO - log:205 - ⚠️ Low price buffer for SOLUSDT: 0 points
210
+ 2026-01-08 08:37:59,349 - scalper - ERROR - log_error:125 - POSITION_CHECK: Error checking positions: Missing some parameters that must be filled in, symbol or settleCoin (ErrCode: 10001) (ErrTime: 14:37:59).
211
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
212
+ 2026-01-08 08:38:00,095 - scalper - ERROR - log_error:125 - POSITION_CHECK: Error checking positions: Missing some parameters that must be filled in, symbol or settleCoin (ErrCode: 10001) (ErrTime: 14:38:00).
213
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
214
+ 2026-01-08 08:38:00,463 - scalper - INFO - log:205 - ⚠️ Low price buffer for BTCUSDT: 0 points
215
+ 2026-01-08 08:38:00,463 - scalper - INFO - log:205 - ⚠️ Low price buffer for ETHUSDT: 0 points
216
+ 2026-01-08 08:38:00,464 - scalper - INFO - log:205 - ⚠️ Low price buffer for SOLUSDT: 0 points
217
+ 2026-01-08 08:38:05,892 - scalper - ERROR - log_error:125 - POSITION_CHECK: Error checking positions: Missing some parameters that must be filled in, symbol or settleCoin (ErrCode: 10001) (ErrTime: 14:38:05).
218
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
219
+ 2026-01-08 08:38:06,687 - scalper - ERROR - log_error:125 - POSITION_CHECK: Error checking positions: Missing some parameters that must be filled in, symbol or settleCoin (ErrCode: 10001) (ErrTime: 14:38:06).
220
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
221
+ 2026-01-08 08:38:07,103 - scalper - INFO - log:205 - ⚠️ Low price buffer for BTCUSDT: 0 points
222
+ 2026-01-08 08:38:07,103 - scalper - INFO - log:205 - ⚠️ Low price buffer for ETHUSDT: 0 points
223
+ 2026-01-08 08:38:07,104 - scalper - INFO - log:205 - ⚠️ Low price buffer for SOLUSDT: 0 points
224
+ 2026-01-08 08:38:12,478 - scalper - ERROR - log_error:125 - POSITION_CHECK: Error checking positions: Missing some parameters that must be filled in, symbol or settleCoin (ErrCode: 10001) (ErrTime: 14:38:12).
225
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
226
+ 2026-01-08 08:38:13,349 - scalper - ERROR - log_error:125 - POSITION_CHECK: Error checking positions: Missing some parameters that must be filled in, symbol or settleCoin (ErrCode: 10001) (ErrTime: 14:38:13).
227
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
228
+ 2026-01-08 08:38:13,741 - scalper - INFO - log:205 - ⚠️ Low price buffer for BTCUSDT: 0 points
229
+ 2026-01-08 08:38:13,742 - scalper - INFO - log:205 - ⚠️ Low price buffer for ETHUSDT: 0 points
230
+ 2026-01-08 08:38:13,742 - scalper - INFO - log:205 - ⚠️ Low price buffer for SOLUSDT: 0 points
231
+ 2026-01-08 08:38:19,573 - scalper - ERROR - log_error:125 - POSITION_CHECK: Error checking positions: Missing some parameters that must be filled in, symbol or settleCoin (ErrCode: 10001) (ErrTime: 14:38:19).
232
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
233
+ 2026-01-08 08:38:20,395 - scalper - ERROR - log_error:125 - POSITION_CHECK: Error checking positions: Missing some parameters that must be filled in, symbol or settleCoin (ErrCode: 10001) (ErrTime: 14:38:20).
234
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
235
+ 2026-01-08 08:38:20,789 - scalper - INFO - log:205 - ⚠️ Low price buffer for BTCUSDT: 0 points
236
+ 2026-01-08 08:38:20,790 - scalper - INFO - log:205 - ⚠️ Low price buffer for ETHUSDT: 0 points
237
+ 2026-01-08 08:38:20,791 - scalper - INFO - log:205 - ⚠️ Low price buffer for SOLUSDT: 0 points
238
+ 2026-01-08 08:38:26,178 - scalper - ERROR - log_error:125 - POSITION_CHECK: Error checking positions: Missing some parameters that must be filled in, symbol or settleCoin (ErrCode: 10001) (ErrTime: 14:38:26).
239
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
240
+ 2026-01-08 08:38:26,976 - scalper - ERROR - log_error:125 - POSITION_CHECK: Error checking positions: Missing some parameters that must be filled in, symbol or settleCoin (ErrCode: 10001) (ErrTime: 14:38:26).
241
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
242
+ 2026-01-08 08:38:27,386 - scalper - INFO - log:205 - ⚠️ Low price buffer for BTCUSDT: 0 points
243
+ 2026-01-08 08:38:27,386 - scalper - INFO - log:205 - ⚠️ Low price buffer for ETHUSDT: 0 points
244
+ 2026-01-08 08:38:27,386 - scalper - INFO - log:205 - ⚠️ Low price buffer for SOLUSDT: 0 points
245
+ 2026-01-08 08:38:32,722 - scalper - ERROR - log_error:125 - POSITION_CHECK: Error checking positions: Missing some parameters that must be filled in, symbol or settleCoin (ErrCode: 10001) (ErrTime: 14:38:32).
246
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
247
+ 2026-01-08 08:38:33,526 - scalper - ERROR - log_error:125 - POSITION_CHECK: Error checking positions: Missing some parameters that must be filled in, symbol or settleCoin (ErrCode: 10001) (ErrTime: 14:38:33).
248
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
249
+ 2026-01-08 08:38:33,896 - scalper - INFO - log:205 - ⚠️ Low price buffer for BTCUSDT: 0 points
250
+ 2026-01-08 08:38:33,896 - scalper - INFO - log:205 - ⚠️ Low price buffer for ETHUSDT: 0 points
251
+ 2026-01-08 08:38:33,896 - scalper - INFO - log:205 - ⚠️ Low price buffer for SOLUSDT: 0 points
252
+ 2026-01-08 08:38:39,332 - scalper - ERROR - log_error:125 - POSITION_CHECK: Error checking positions: Missing some parameters that must be filled in, symbol or settleCoin (ErrCode: 10001) (ErrTime: 14:38:39).
253
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
254
+ 2026-01-08 08:38:40,099 - scalper - ERROR - log_error:125 - POSITION_CHECK: Error checking positions: Missing some parameters that must be filled in, symbol or settleCoin (ErrCode: 10001) (ErrTime: 14:38:40).
255
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
256
+ 2026-01-08 08:38:40,484 - scalper - INFO - log:205 - ⚠️ Low price buffer for BTCUSDT: 0 points
257
+ 2026-01-08 08:38:40,489 - scalper - INFO - log:205 - ⚠️ Low price buffer for ETHUSDT: 0 points
258
+ 2026-01-08 08:38:40,489 - scalper - INFO - log:205 - ⚠️ Low price buffer for SOLUSDT: 0 points
259
+ 2026-01-08 08:38:45,994 - scalper - ERROR - log_error:125 - POSITION_CHECK: Error checking positions: Missing some parameters that must be filled in, symbol or settleCoin (ErrCode: 10001) (ErrTime: 14:38:45).
260
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
261
+ 2026-01-08 08:38:46,691 - scalper - ERROR - log_error:125 - POSITION_CHECK: Error checking positions: Missing some parameters that must be filled in, symbol or settleCoin (ErrCode: 10001) (ErrTime: 14:38:46).
262
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
263
+ 2026-01-08 08:38:47,063 - scalper - INFO - log:205 - ⚠️ Low price buffer for BTCUSDT: 0 points
264
+ 2026-01-08 08:38:47,064 - scalper - INFO - log:205 - ⚠️ Low price buffer for ETHUSDT: 0 points
265
+ 2026-01-08 08:38:47,064 - scalper - INFO - log:205 - ⚠️ Low price buffer for SOLUSDT: 0 points
266
+ 2026-01-08 08:38:52,626 - scalper - ERROR - log_error:125 - POSITION_CHECK: Error checking positions: Missing some parameters that must be filled in, symbol or settleCoin (ErrCode: 10001) (ErrTime: 14:38:52).
267
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
268
+ 2026-01-08 08:38:53,552 - scalper - ERROR - log_error:125 - POSITION_CHECK: Error checking positions: Missing some parameters that must be filled in, symbol or settleCoin (ErrCode: 10001) (ErrTime: 14:38:53).
269
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
270
+ 2026-01-08 08:38:53,979 - scalper - INFO - log:205 - ⚠️ Low price buffer for BTCUSDT: 0 points
271
+ 2026-01-08 08:38:53,985 - scalper - INFO - log:205 - ⚠️ Low price buffer for ETHUSDT: 0 points
272
+ 2026-01-08 08:38:53,987 - scalper - INFO - log:205 - ⚠️ Low price buffer for SOLUSDT: 0 points
273
+ 2026-01-08 08:38:59,186 - scalper - ERROR - log_error:125 - POSITION_CHECK: Error checking positions: Missing some parameters that must be filled in, symbol or settleCoin (ErrCode: 10001) (ErrTime: 14:38:59).
274
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
275
+ 2026-01-08 08:39:00,123 - scalper - ERROR - log_error:125 - POSITION_CHECK: Error checking positions: Missing some parameters that must be filled in, symbol or settleCoin (ErrCode: 10001) (ErrTime: 14:39:00).
276
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
277
+ 2026-01-08 08:39:00,571 - scalper - INFO - log:205 - ⚠️ Low price buffer for BTCUSDT: 0 points
278
+ 2026-01-08 08:39:00,582 - scalper - INFO - log:205 - ⚠️ Low price buffer for ETHUSDT: 0 points
279
+ 2026-01-08 08:39:00,582 - scalper - INFO - log:205 - ⚠️ Low price buffer for SOLUSDT: 0 points
280
+ 2026-01-08 08:39:05,847 - scalper - ERROR - log_error:125 - POSITION_CHECK: Error checking positions: Missing some parameters that must be filled in, symbol or settleCoin (ErrCode: 10001) (ErrTime: 14:39:05).
281
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
282
+ 2026-01-08 08:39:06,742 - scalper - ERROR - log_error:125 - POSITION_CHECK: Error checking positions: Missing some parameters that must be filled in, symbol or settleCoin (ErrCode: 10001) (ErrTime: 14:39:06).
283
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
284
+ 2026-01-08 08:39:06,743 - scalper - INFO - log_performance:140 - PERFORMANCE - ALL (5min): emergency_stop: 0.00, open_positions: 0.00, daily_pnl: 0.00, daily_trades: 0.00, win_rate: 0.00, total_trades: 0.00, positions: [], total_pnl: 0.00
285
+ 2026-01-08 08:39:07,112 - scalper - INFO - log:205 - ⚠️ Low price buffer for BTCUSDT: 0 points
286
+ 2026-01-08 08:39:07,112 - scalper - INFO - log:205 - ⚠️ Low price buffer for ETHUSDT: 0 points
287
+ 2026-01-08 08:39:07,112 - scalper - INFO - log:205 - ⚠️ Low price buffer for SOLUSDT: 0 points
288
+ 2026-01-08 08:39:12,351 - scalper - ERROR - log_error:125 - POSITION_CHECK: Error checking positions: Missing some parameters that must be filled in, symbol or settleCoin (ErrCode: 10001) (ErrTime: 14:39:12).
289
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
290
+ 2026-01-08 08:39:13,238 - scalper - ERROR - log_error:125 - POSITION_CHECK: Error checking positions: Missing some parameters that must be filled in, symbol or settleCoin (ErrCode: 10001) (ErrTime: 14:39:13).
291
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
292
+ 2026-01-08 08:39:13,615 - scalper - INFO - log:205 - ⚠️ Low price buffer for BTCUSDT: 0 points
293
+ 2026-01-08 08:39:13,615 - scalper - INFO - log:205 - ⚠️ Low price buffer for ETHUSDT: 0 points
294
+ 2026-01-08 08:39:13,615 - scalper - INFO - log:205 - ⚠️ Low price buffer for SOLUSDT: 0 points
295
+ 2026-01-08 08:39:18,856 - scalper - ERROR - log_error:125 - POSITION_CHECK: Error checking positions: Missing some parameters that must be filled in, symbol or settleCoin (ErrCode: 10001) (ErrTime: 14:39:18).
296
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
297
+ 2026-01-08 08:39:19,812 - scalper - ERROR - log_error:125 - POSITION_CHECK: Error checking positions: Missing some parameters that must be filled in, symbol or settleCoin (ErrCode: 10001) (ErrTime: 14:39:19).
298
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
299
+ 2026-01-08 08:39:20,180 - scalper - INFO - log:205 - ⚠️ Low price buffer for BTCUSDT: 0 points
300
+ 2026-01-08 08:39:20,181 - scalper - INFO - log:205 - ⚠️ Low price buffer for ETHUSDT: 0 points
301
+ 2026-01-08 08:39:20,181 - scalper - INFO - log:205 - ⚠️ Low price buffer for SOLUSDT: 0 points
302
+ 2026-01-08 08:39:25,602 - scalper - ERROR - log_error:125 - POSITION_CHECK: Error checking positions: Missing some parameters that must be filled in, symbol or settleCoin (ErrCode: 10001) (ErrTime: 14:39:25).
303
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
304
+ 2026-01-08 08:39:26,333 - scalper - ERROR - log_error:125 - POSITION_CHECK: Error checking positions: Missing some parameters that must be filled in, symbol or settleCoin (ErrCode: 10001) (ErrTime: 14:39:26).
305
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
306
+ 2026-01-08 08:39:26,716 - scalper - INFO - log:205 - ⚠️ Low price buffer for BTCUSDT: 0 points
307
+ 2026-01-08 08:39:26,716 - scalper - INFO - log:205 - ⚠️ Low price buffer for ETHUSDT: 0 points
308
+ 2026-01-08 08:39:26,716 - scalper - INFO - log:205 - ⚠️ Low price buffer for SOLUSDT: 0 points
309
+ 2026-01-08 08:39:32,309 - scalper - ERROR - log_error:125 - POSITION_CHECK: Error checking positions: Missing some parameters that must be filled in, symbol or settleCoin (ErrCode: 10001) (ErrTime: 14:39:32).
310
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
311
+ 2026-01-08 08:39:32,992 - scalper - ERROR - log_error:125 - POSITION_CHECK: Error checking positions: Missing some parameters that must be filled in, symbol or settleCoin (ErrCode: 10001) (ErrTime: 14:39:32).
312
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
313
+ 2026-01-08 08:39:33,690 - scalper - INFO - log:205 - ⚠️ Low price buffer for BTCUSDT: 0 points
314
+ 2026-01-08 08:39:33,690 - scalper - INFO - log:205 - ⚠️ Low price buffer for ETHUSDT: 0 points
315
+ 2026-01-08 08:39:33,690 - scalper - INFO - log:205 - ⚠️ Low price buffer for SOLUSDT: 0 points
316
+ 2026-01-08 08:39:38,808 - scalper - ERROR - log_error:125 - POSITION_CHECK: Error checking positions: Missing some parameters that must be filled in, symbol or settleCoin (ErrCode: 10001) (ErrTime: 14:39:38).
317
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
318
+ 2026-01-08 08:39:39,878 - scalper - ERROR - log_error:125 - POSITION_CHECK: Error checking positions: Missing some parameters that must be filled in, symbol or settleCoin (ErrCode: 10001) (ErrTime: 14:39:39).
319
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
320
+ 2026-01-08 08:39:40,254 - scalper - INFO - log:205 - ⚠️ Low price buffer for BTCUSDT: 0 points
321
+ 2026-01-08 08:39:40,254 - scalper - INFO - log:205 - ⚠️ Low price buffer for ETHUSDT: 0 points
322
+ 2026-01-08 08:39:40,255 - scalper - INFO - log:205 - ⚠️ Low price buffer for SOLUSDT: 0 points
323
+ 2026-01-08 08:39:45,492 - scalper - ERROR - log_error:125 - POSITION_CHECK: Error checking positions: Missing some parameters that must be filled in, symbol or settleCoin (ErrCode: 10001) (ErrTime: 14:39:45).
324
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
325
+ 2026-01-08 08:39:46,402 - scalper - ERROR - log_error:125 - POSITION_CHECK: Error checking positions: Missing some parameters that must be filled in, symbol or settleCoin (ErrCode: 10001) (ErrTime: 14:39:46).
326
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
327
+ 2026-01-08 08:39:46,780 - scalper - INFO - log:205 - ⚠️ Low price buffer for BTCUSDT: 0 points
328
+ 2026-01-08 08:39:46,780 - scalper - INFO - log:205 - ⚠️ Low price buffer for ETHUSDT: 0 points
329
+ 2026-01-08 08:39:46,780 - scalper - INFO - log:205 - ⚠️ Low price buffer for SOLUSDT: 0 points
330
+ 2026-01-08 08:39:52,342 - scalper - ERROR - log_error:125 - POSITION_CHECK: Error checking positions: Missing some parameters that must be filled in, symbol or settleCoin (ErrCode: 10001) (ErrTime: 14:39:52).
331
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
332
+ 2026-01-08 08:39:52,896 - scalper - ERROR - log_error:125 - POSITION_CHECK: Error checking positions: Missing some parameters that must be filled in, symbol or settleCoin (ErrCode: 10001) (ErrTime: 14:39:52).
333
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
334
+ 2026-01-08 08:39:53,272 - scalper - INFO - log:205 - ⚠️ Low price buffer for BTCUSDT: 0 points
335
+ 2026-01-08 08:39:53,272 - scalper - INFO - log:205 - ⚠️ Low price buffer for ETHUSDT: 0 points
336
+ 2026-01-08 08:39:53,272 - scalper - INFO - log:205 - ⚠️ Low price buffer for SOLUSDT: 0 points
337
+ 2026-01-08 08:39:59,328 - scalper - ERROR - log_error:125 - POSITION_CHECK: Error checking positions: Missing some parameters that must be filled in, symbol or settleCoin (ErrCode: 10001) (ErrTime: 14:39:59).
338
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
339
+ 2026-01-08 08:39:59,702 - scalper - ERROR - log_error:125 - POSITION_CHECK: Error checking positions: Missing some parameters that must be filled in, symbol or settleCoin (ErrCode: 10001) (ErrTime: 14:39:59).
340
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
341
+ 2026-01-08 08:40:00,070 - scalper - INFO - log:205 - ⚠️ Low price buffer for BTCUSDT: 0 points
342
+ 2026-01-08 08:40:00,071 - scalper - INFO - log:205 - ⚠️ Low price buffer for ETHUSDT: 0 points
343
+ 2026-01-08 08:40:00,071 - scalper - INFO - log:205 - ⚠️ Low price buffer for SOLUSDT: 0 points
344
+ 2026-01-08 08:40:05,835 - scalper - ERROR - log_error:125 - POSITION_CHECK: Error checking positions: Missing some parameters that must be filled in, symbol or settleCoin (ErrCode: 10001) (ErrTime: 14:40:05).
345
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
346
+ 2026-01-08 08:40:06,262 - scalper - ERROR - log_error:125 - POSITION_CHECK: Error checking positions: Missing some parameters that must be filled in, symbol or settleCoin (ErrCode: 10001) (ErrTime: 14:40:06).
347
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
348
+ 2026-01-08 08:40:06,649 - scalper - INFO - log:205 - ⚠️ Low price buffer for BTCUSDT: 0 points
349
+ 2026-01-08 08:40:06,650 - scalper - INFO - log:205 - ⚠️ Low price buffer for ETHUSDT: 0 points
350
+ 2026-01-08 08:40:06,650 - scalper - INFO - log:205 - ⚠️ Low price buffer for SOLUSDT: 0 points
351
+ 2026-01-08 08:40:12,407 - scalper - ERROR - log_error:125 - POSITION_CHECK: Error checking positions: Missing some parameters that must be filled in, symbol or settleCoin (ErrCode: 10001) (ErrTime: 14:40:12).
352
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
353
+ 2026-01-08 08:40:12,801 - scalper - ERROR - log_error:125 - POSITION_CHECK: Error checking positions: Missing some parameters that must be filled in, symbol or settleCoin (ErrCode: 10001) (ErrTime: 14:40:12).
354
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
355
+ 2026-01-08 08:40:13,171 - scalper - INFO - log:205 - ⚠️ Low price buffer for BTCUSDT: 0 points
356
+ 2026-01-08 08:40:13,172 - scalper - INFO - log:205 - ⚠️ Low price buffer for ETHUSDT: 0 points
357
+ 2026-01-08 08:40:13,172 - scalper - INFO - log:205 - ⚠️ Low price buffer for SOLUSDT: 0 points
358
+ 2026-01-08 08:40:18,963 - scalper - ERROR - log_error:125 - POSITION_CHECK: Error checking positions: Missing some parameters that must be filled in, symbol or settleCoin (ErrCode: 10001) (ErrTime: 14:40:18).
359
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
360
+ 2026-01-08 08:40:19,325 - scalper - ERROR - log_error:125 - POSITION_CHECK: Error checking positions: Missing some parameters that must be filled in, symbol or settleCoin (ErrCode: 10001) (ErrTime: 14:40:19).
361
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
362
+ 2026-01-08 08:40:19,710 - scalper - INFO - log:205 - ⚠️ Low price buffer for BTCUSDT: 0 points
363
+ 2026-01-08 08:40:19,710 - scalper - INFO - log:205 - ⚠️ Low price buffer for ETHUSDT: 0 points
364
+ 2026-01-08 08:40:19,711 - scalper - INFO - log:205 - ⚠️ Low price buffer for SOLUSDT: 0 points
365
+ 2026-01-08 08:40:25,470 - scalper - ERROR - log_error:125 - POSITION_CHECK: Error checking positions: Missing some parameters that must be filled in, symbol or settleCoin (ErrCode: 10001) (ErrTime: 14:40:25).
366
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
367
+ 2026-01-08 08:40:25,835 - scalper - ERROR - log_error:125 - POSITION_CHECK: Error checking positions: Missing some parameters that must be filled in, symbol or settleCoin (ErrCode: 10001) (ErrTime: 14:40:25).
368
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
369
+ 2026-01-08 08:40:26,222 - scalper - INFO - log:205 - ⚠️ Low price buffer for BTCUSDT: 0 points
370
+ 2026-01-08 08:40:26,222 - scalper - INFO - log:205 - ⚠️ Low price buffer for ETHUSDT: 0 points
371
+ 2026-01-08 08:40:26,222 - scalper - INFO - log:205 - ⚠️ Low price buffer for SOLUSDT: 0 points
372
+ 2026-01-08 09:18:16,857 - scalper - ERROR - log_error:125 - POSITION_CHECK: Error checking positions: HTTPSConnectionPool(host='api.bybit.com', port=443): Max retries exceeded with url: /v5/position/list?category=linear (Caused by NameResolutionError("<urllib3.connection.HTTPSConnection object at 0x7fa8c7dadbe0>: Failed to resolve 'api.bybit.com' ([Errno -3] Temporary failure in name resolution)"))
373
+ 2026-01-08 09:18:16,925 - scalper - INFO - log_performance:140 - PERFORMANCE - ALL (5min): emergency_stop: 0.00, open_positions: 0.00, daily_pnl: 0.00, daily_trades: 0.00, win_rate: 0.00, total_trades: 0.00, positions: [], total_pnl: 0.00
374
+ 2026-01-08 09:18:17,152 - scalper - ERROR - log_error:125 - POSITION_CHECK: Error checking positions: HTTPSConnectionPool(host='api.bybit.com', port=443): Max retries exceeded with url: /v5/position/list?category=linear (Caused by NameResolutionError("<urllib3.connection.HTTPSConnection object at 0x7f87b3572900>: Failed to resolve 'api.bybit.com' ([Errno -3] Temporary failure in name resolution)"))
375
+ 2026-01-08 09:18:17,152 - scalper - INFO - log_performance:140 - PERFORMANCE - ALL (5min): emergency_stop: 0.00, open_positions: 0.00, daily_pnl: 0.00, daily_trades: 0.00, win_rate: 0.00, total_trades: 0.00, positions: [], total_pnl: 0.00
376
+ 2026-01-08 09:18:20,913 - scalper - INFO - log:205 - ⚠️ Low price buffer for BTCUSDT: 0 points
377
+ 2026-01-08 09:18:20,913 - scalper - INFO - log:205 - ⚠️ Low price buffer for ETHUSDT: 0 points
378
+ 2026-01-08 09:18:20,913 - scalper - INFO - log:205 - ⚠️ Low price buffer for SOLUSDT: 0 points
379
+ 2026-01-08 09:18:27,355 - scalper - ERROR - log_error:125 - POSITION_CHECK: Error checking positions: Unmatched IP, please check your API key's bound IP addresses. (ErrCode: 10010) (ErrTime: 15:18:27).
380
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
381
+ 2026-01-08 09:18:27,661 - scalper - INFO - log:205 - ⚠️ Low price buffer for BTCUSDT: 0 points
382
+ 2026-01-08 09:18:27,661 - scalper - INFO - log:205 - ⚠️ Low price buffer for ETHUSDT: 0 points
383
+ 2026-01-08 09:18:27,661 - scalper - INFO - log:205 - ⚠️ Low price buffer for SOLUSDT: 0 points
384
+ 2026-01-08 09:18:27,775 - scalper - ERROR - log_error:125 - POSITION_CHECK: Error checking positions: Unmatched IP, please check your API key's bound IP addresses. (ErrCode: 10010) (ErrTime: 15:18:27).
385
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
386
+ 2026-01-08 09:18:33,629 - scalper - ERROR - log_error:125 - POSITION_CHECK: Error checking positions: Unmatched IP, please check your API key's bound IP addresses. (ErrCode: 10010) (ErrTime: 15:18:33).
387
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
388
+ 2026-01-08 09:18:33,942 - scalper - INFO - log:205 - ⚠️ Low price buffer for BTCUSDT: 0 points
389
+ 2026-01-08 09:18:33,942 - scalper - INFO - log:205 - ⚠️ Low price buffer for ETHUSDT: 0 points
390
+ 2026-01-08 09:18:33,942 - scalper - INFO - log:205 - ⚠️ Low price buffer for SOLUSDT: 0 points
391
+ 2026-01-08 09:18:34,384 - scalper - ERROR - log_error:125 - POSITION_CHECK: Error checking positions: Unmatched IP, please check your API key's bound IP addresses. (ErrCode: 10010) (ErrTime: 15:18:34).
392
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
393
+ 2026-01-08 09:18:39,888 - scalper - ERROR - log_error:125 - POSITION_CHECK: Error checking positions: Unmatched IP, please check your API key's bound IP addresses. (ErrCode: 10010) (ErrTime: 15:18:39).
394
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
395
+ 2026-01-08 09:18:40,197 - scalper - INFO - log:205 - ⚠️ Low price buffer for BTCUSDT: 0 points
396
+ 2026-01-08 09:18:40,198 - scalper - INFO - log:205 - ⚠️ Low price buffer for ETHUSDT: 0 points
397
+ 2026-01-08 09:18:40,198 - scalper - INFO - log:205 - ⚠️ Low price buffer for SOLUSDT: 0 points
398
+ 2026-01-08 09:18:40,635 - scalper - ERROR - log_error:125 - POSITION_CHECK: Error checking positions: Unmatched IP, please check your API key's bound IP addresses. (ErrCode: 10010) (ErrTime: 15:18:40).
399
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
400
+ 2026-01-08 09:18:46,160 - scalper - ERROR - log_error:125 - POSITION_CHECK: Error checking positions: Unmatched IP, please check your API key's bound IP addresses. (ErrCode: 10010) (ErrTime: 15:18:46).
401
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
402
+ 2026-01-08 09:18:46,478 - scalper - INFO - log:205 - ⚠️ Low price buffer for BTCUSDT: 0 points
403
+ 2026-01-08 09:18:46,478 - scalper - INFO - log:205 - ⚠️ Low price buffer for ETHUSDT: 0 points
404
+ 2026-01-08 09:18:46,479 - scalper - INFO - log:205 - ⚠️ Low price buffer for SOLUSDT: 0 points
405
+ 2026-01-08 09:18:46,923 - scalper - ERROR - log_error:125 - POSITION_CHECK: Error checking positions: Unmatched IP, please check your API key's bound IP addresses. (ErrCode: 10010) (ErrTime: 15:18:46).
406
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
407
+ 2026-01-08 09:18:52,447 - scalper - ERROR - log_error:125 - POSITION_CHECK: Error checking positions: Unmatched IP, please check your API key's bound IP addresses. (ErrCode: 10010) (ErrTime: 15:18:52).
408
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
409
+ 2026-01-08 09:18:52,763 - scalper - INFO - log:205 - ⚠️ Low price buffer for BTCUSDT: 0 points
410
+ 2026-01-08 09:18:52,763 - scalper - INFO - log:205 - ⚠️ Low price buffer for ETHUSDT: 0 points
411
+ 2026-01-08 09:18:52,764 - scalper - INFO - log:205 - ⚠️ Low price buffer for SOLUSDT: 0 points
412
+ 2026-01-08 09:18:53,247 - scalper - ERROR - log_error:125 - POSITION_CHECK: Error checking positions: Unmatched IP, please check your API key's bound IP addresses. (ErrCode: 10010) (ErrTime: 15:18:53).
413
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
414
+ 2026-01-08 09:18:58,713 - scalper - ERROR - log_error:125 - POSITION_CHECK: Error checking positions: Unmatched IP, please check your API key's bound IP addresses. (ErrCode: 10010) (ErrTime: 15:18:58).
415
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
416
+ 2026-01-08 09:18:59,036 - scalper - INFO - log:205 - ⚠️ Low price buffer for BTCUSDT: 0 points
417
+ 2026-01-08 09:18:59,036 - scalper - INFO - log:205 - ⚠️ Low price buffer for ETHUSDT: 0 points
418
+ 2026-01-08 09:18:59,037 - scalper - INFO - log:205 - ⚠️ Low price buffer for SOLUSDT: 0 points
419
+ 2026-01-08 09:18:59,869 - scalper - ERROR - log_error:125 - POSITION_CHECK: Error checking positions: Unmatched IP, please check your API key's bound IP addresses. (ErrCode: 10010) (ErrTime: 15:18:59).
420
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
421
+ 2026-01-08 09:19:04,983 - scalper - ERROR - log_error:125 - POSITION_CHECK: Error checking positions: Unmatched IP, please check your API key's bound IP addresses. (ErrCode: 10010) (ErrTime: 15:19:04).
422
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
423
+ 2026-01-08 09:19:05,321 - scalper - INFO - log:205 - ⚠️ Low price buffer for BTCUSDT: 0 points
424
+ 2026-01-08 09:19:05,322 - scalper - INFO - log:205 - ⚠️ Low price buffer for ETHUSDT: 0 points
425
+ 2026-01-08 09:19:05,322 - scalper - INFO - log:205 - ⚠️ Low price buffer for SOLUSDT: 0 points
426
+ 2026-01-08 09:19:06,149 - scalper - ERROR - log_error:125 - POSITION_CHECK: Error checking positions: Unmatched IP, please check your API key's bound IP addresses. (ErrCode: 10010) (ErrTime: 15:19:06).
427
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
428
+ 2026-01-08 09:19:11,307 - scalper - ERROR - log_error:125 - POSITION_CHECK: Error checking positions: Unmatched IP, please check your API key's bound IP addresses. (ErrCode: 10010) (ErrTime: 15:19:11).
429
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
430
+ 2026-01-08 09:19:11,621 - scalper - INFO - log:205 - ⚠️ Low price buffer for BTCUSDT: 0 points
431
+ 2026-01-08 09:19:11,621 - scalper - INFO - log:205 - ⚠️ Low price buffer for ETHUSDT: 0 points
432
+ 2026-01-08 09:19:11,621 - scalper - INFO - log:205 - ⚠️ Low price buffer for SOLUSDT: 0 points
433
+ 2026-01-08 09:19:12,464 - scalper - ERROR - log_error:125 - POSITION_CHECK: Error checking positions: Unmatched IP, please check your API key's bound IP addresses. (ErrCode: 10010) (ErrTime: 15:19:12).
434
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
435
+ 2026-01-08 09:19:17,567 - scalper - ERROR - log_error:125 - POSITION_CHECK: Error checking positions: Unmatched IP, please check your API key's bound IP addresses. (ErrCode: 10010) (ErrTime: 15:19:17).
436
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
437
+ 2026-01-08 09:19:17,875 - scalper - INFO - log:205 - ⚠️ Low price buffer for BTCUSDT: 0 points
438
+ 2026-01-08 09:19:17,875 - scalper - INFO - log:205 - ⚠️ Low price buffer for ETHUSDT: 0 points
439
+ 2026-01-08 09:19:17,875 - scalper - INFO - log:205 - ⚠️ Low price buffer for SOLUSDT: 0 points
440
+ 2026-01-08 09:19:18,735 - scalper - ERROR - log_error:125 - POSITION_CHECK: Error checking positions: Unmatched IP, please check your API key's bound IP addresses. (ErrCode: 10010) (ErrTime: 15:19:18).
441
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
442
+ 2026-01-08 09:19:23,898 - scalper - ERROR - log_error:125 - POSITION_CHECK: Error checking positions: Unmatched IP, please check your API key's bound IP addresses. (ErrCode: 10010) (ErrTime: 15:19:23).
443
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
444
+ 2026-01-08 09:19:24,249 - scalper - INFO - log:205 - ⚠️ Low price buffer for BTCUSDT: 0 points
445
+ 2026-01-08 09:19:24,249 - scalper - INFO - log:205 - ⚠️ Low price buffer for ETHUSDT: 0 points
446
+ 2026-01-08 09:19:24,250 - scalper - INFO - log:205 - ⚠️ Low price buffer for SOLUSDT: 0 points
447
+ 2026-01-08 09:19:25,033 - scalper - ERROR - log_error:125 - POSITION_CHECK: Error checking positions: Unmatched IP, please check your API key's bound IP addresses. (ErrCode: 10010) (ErrTime: 15:19:25).
448
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
449
+ 2026-01-08 09:19:30,217 - scalper - ERROR - log_error:125 - POSITION_CHECK: Error checking positions: Unmatched IP, please check your API key's bound IP addresses. (ErrCode: 10010) (ErrTime: 15:19:30).
450
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
451
+ 2026-01-08 09:19:30,551 - scalper - INFO - log:205 - ⚠️ Low price buffer for BTCUSDT: 0 points
452
+ 2026-01-08 09:19:30,551 - scalper - INFO - log:205 - ⚠️ Low price buffer for ETHUSDT: 0 points
453
+ 2026-01-08 09:19:30,552 - scalper - INFO - log:205 - ⚠️ Low price buffer for SOLUSDT: 0 points
454
+ 2026-01-08 09:19:31,983 - scalper - ERROR - log_error:125 - POSITION_CHECK: Error checking positions: Unmatched IP, please check your API key's bound IP addresses. (ErrCode: 10010) (ErrTime: 15:19:31).
455
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
456
+ 2026-01-08 09:19:36,549 - scalper - ERROR - log_error:125 - POSITION_CHECK: Error checking positions: Unmatched IP, please check your API key's bound IP addresses. (ErrCode: 10010) (ErrTime: 15:19:36).
457
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
458
+ 2026-01-08 09:19:36,882 - scalper - INFO - log:205 - ⚠️ Low price buffer for BTCUSDT: 0 points
459
+ 2026-01-08 09:19:36,882 - scalper - INFO - log:205 - ⚠️ Low price buffer for ETHUSDT: 0 points
460
+ 2026-01-08 09:19:36,882 - scalper - INFO - log:205 - ⚠️ Low price buffer for SOLUSDT: 0 points
461
+ 2026-01-08 09:19:38,289 - scalper - ERROR - log_error:125 - POSITION_CHECK: Error checking positions: Unmatched IP, please check your API key's bound IP addresses. (ErrCode: 10010) (ErrTime: 15:19:38).
462
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
463
+ 2026-01-08 09:19:42,883 - scalper - ERROR - log_error:125 - POSITION_CHECK: Error checking positions: Unmatched IP, please check your API key's bound IP addresses. (ErrCode: 10010) (ErrTime: 15:19:42).
464
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
465
+ 2026-01-08 09:19:43,200 - scalper - INFO - log:205 - ⚠️ Low price buffer for BTCUSDT: 0 points
466
+ 2026-01-08 09:19:43,201 - scalper - INFO - log:205 - ⚠️ Low price buffer for ETHUSDT: 0 points
467
+ 2026-01-08 09:19:43,201 - scalper - INFO - log:205 - ⚠️ Low price buffer for SOLUSDT: 0 points
468
+ 2026-01-08 09:19:44,959 - scalper - ERROR - log_error:125 - POSITION_CHECK: Error checking positions: Unmatched IP, please check your API key's bound IP addresses. (ErrCode: 10010) (ErrTime: 15:19:44).
469
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
470
+ 2026-01-08 09:19:49,179 - scalper - ERROR - log_error:125 - POSITION_CHECK: Error checking positions: Unmatched IP, please check your API key's bound IP addresses. (ErrCode: 10010) (ErrTime: 15:19:49).
471
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
472
+ 2026-01-08 09:19:49,815 - scalper - INFO - log:205 - ⚠️ Low price buffer for BTCUSDT: 0 points
473
+ 2026-01-08 09:19:49,815 - scalper - INFO - log:205 - ⚠️ Low price buffer for ETHUSDT: 0 points
474
+ 2026-01-08 09:19:49,815 - scalper - INFO - log:205 - ⚠️ Low price buffer for SOLUSDT: 0 points
475
+ 2026-01-08 09:19:51,268 - scalper - ERROR - log_error:125 - POSITION_CHECK: Error checking positions: Unmatched IP, please check your API key's bound IP addresses. (ErrCode: 10010) (ErrTime: 15:19:51).
476
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
477
+ 2026-01-08 09:19:56,099 - scalper - ERROR - log_error:125 - POSITION_CHECK: Error checking positions: Unmatched IP, please check your API key's bound IP addresses. (ErrCode: 10010) (ErrTime: 15:19:56).
478
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
479
+ 2026-01-08 09:19:56,432 - scalper - INFO - log:205 - ⚠️ Low price buffer for BTCUSDT: 0 points
480
+ 2026-01-08 09:19:56,432 - scalper - INFO - log:205 - ⚠️ Low price buffer for ETHUSDT: 0 points
481
+ 2026-01-08 09:19:56,432 - scalper - INFO - log:205 - ⚠️ Low price buffer for SOLUSDT: 0 points
482
+ 2026-01-08 09:19:57,589 - scalper - ERROR - log_error:125 - POSITION_CHECK: Error checking positions: Unmatched IP, please check your API key's bound IP addresses. (ErrCode: 10010) (ErrTime: 15:19:57).
483
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
484
+ 2026-01-08 09:20:02,381 - scalper - ERROR - log_error:125 - POSITION_CHECK: Error checking positions: Unmatched IP, please check your API key's bound IP addresses. (ErrCode: 10010) (ErrTime: 15:20:02).
485
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
486
+ 2026-01-08 09:20:02,695 - scalper - INFO - log:205 - ⚠️ Low price buffer for BTCUSDT: 0 points
487
+ 2026-01-08 09:20:02,696 - scalper - INFO - log:205 - ⚠️ Low price buffer for ETHUSDT: 0 points
488
+ 2026-01-08 09:20:02,696 - scalper - INFO - log:205 - ⚠️ Low price buffer for SOLUSDT: 0 points
489
+ 2026-01-08 09:20:03,432 - scalper - INFO - log:205 - πŸ›‘ Shutdown signal received
490
+ 2026-01-08 09:20:03,434 - scalper - INFO - log:205 - πŸ›‘ Shutdown signal received
491
+ 2026-01-08 09:20:03,854 - scalper - ERROR - log_error:125 - POSITION_CHECK: Error checking positions: Unmatched IP, please check your API key's bound IP addresses. (ErrCode: 10010) (ErrTime: 15:20:03).
492
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
493
+ 2026-01-08 09:20:08,654 - scalper - ERROR - log_error:125 - POSITION_CHECK: Error checking positions: Unmatched IP, please check your API key's bound IP addresses. (ErrCode: 10010) (ErrTime: 15:20:08).
494
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
495
+ 2026-01-08 09:20:09,284 - scalper - INFO - log:205 - ⚠️ Low price buffer for BTCUSDT: 0 points
496
+ 2026-01-08 09:20:09,286 - scalper - INFO - log:205 - ⚠️ Low price buffer for ETHUSDT: 0 points
497
+ 2026-01-08 09:20:09,287 - scalper - INFO - log:205 - ⚠️ Low price buffer for SOLUSDT: 0 points
498
+ 2026-01-08 09:20:10,120 - scalper - ERROR - log_error:125 - POSITION_CHECK: Error checking positions: Unmatched IP, please check your API key's bound IP addresses. (ErrCode: 10010) (ErrTime: 15:20:10).
499
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
500
+ 2026-01-08 09:20:15,315 - scalper - ERROR - log_error:125 - POSITION_CHECK: Error checking positions: Unmatched IP, please check your API key's bound IP addresses. (ErrCode: 10010) (ErrTime: 15:20:15).
501
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
502
+ 2026-01-08 09:20:15,631 - scalper - INFO - log:205 - ⚠️ Low price buffer for BTCUSDT: 0 points
503
+ 2026-01-08 09:20:15,632 - scalper - INFO - log:205 - ⚠️ Low price buffer for ETHUSDT: 0 points
504
+ 2026-01-08 09:20:15,632 - scalper - INFO - log:205 - ⚠️ Low price buffer for SOLUSDT: 0 points
505
+ 2026-01-08 09:20:16,417 - scalper - ERROR - log_error:125 - POSITION_CHECK: Error checking positions: Unmatched IP, please check your API key's bound IP addresses. (ErrCode: 10010) (ErrTime: 15:20:16).
506
+ Request β†’ GET https://api.bybit.com/v5/position/list: category=linear.
507
+ 2026-01-08 09:33:54,347 - scalper - INFO - log:205 - πŸš€ Starting FastAPI server for Bybit Scalping Bot
508
+ 2026-01-08 09:38:22,572 - scalper - INFO - log:205 - πŸš€ Starting FastAPI server for Bybit Scalping Bot
509
+ 2026-01-08 09:39:30,629 - scalper - INFO - log:205 - πŸš€ Started trading session for BTCUSDT (18h duration)
510
+ 2026-01-08 09:39:30,631 - scalper - INFO - log:205 - πŸš€ Starting trading session for BTCUSDT (Duration: 18h)
511
+ 2026-01-08 10:39:14,500 - scalper - INFO - log:205 - πŸ›‘ Trade monitoring stopped
512
+ 2026-01-08 10:39:15,586 - scalper - INFO - log:205 - πŸ›‘ Stopped trading for BTCUSDT
logs/trades.log ADDED
File without changes
main.py ADDED
@@ -0,0 +1,143 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+ """
3
+ Bybit Scalping Bot - FastAPI Control Interface
4
+
5
+ This bot now uses FastAPI for remote control instead of direct command line operation.
6
+ Use the API endpoints to start/stop trading sessions for individual pairs.
7
+
8
+ API Endpoints:
9
+ - GET /status - Get bot status
10
+ - POST /start/{symbol} - Start trading for a symbol (18h default)
11
+ - POST /stop/{symbol} - Stop trading for a symbol
12
+ - GET /sessions - Get all trading sessions
13
+ - GET /report/{session_id} - Get session report
14
+ - POST /emergency_stop - Emergency stop all trading
15
+
16
+ Examples:
17
+ - Start BTC trading: POST /start/BTCUSDT
18
+ - Stop ETH trading: POST /stop/ETHUSDT
19
+ - Check status: GET /status
20
+ """
21
+
22
+ import sys
23
+ import subprocess
24
+ import os
25
+
26
+ def show_usage():
27
+ print("""
28
+ πŸš€ Bybit Scalping Bot - FastAPI Control Interface
29
+ ═══════════════════════════════════════════════════
30
+
31
+ πŸ“‘ API SERVER CONTROL:
32
+ β€’ Start API Server: python api_server.py
33
+ β€’ Server runs on: http://localhost:8000
34
+
35
+ πŸ”— API ENDPOINTS:
36
+
37
+ GET /status
38
+ Returns current bot status and active sessions
39
+
40
+ POST /start/{symbol}?duration_hours=18
41
+ Start trading session for specific symbol
42
+ Examples:
43
+ β€’ POST /start/BTCUSDT
44
+ β€’ POST /start/ETHUSDT?duration_hours=24
45
+
46
+ POST /stop/{symbol}
47
+ Stop trading session for specific symbol
48
+ Example: POST /stop/BTCUSDT
49
+
50
+ GET /sessions
51
+ Get all trading sessions (active and completed)
52
+
53
+ GET /report/{session_id}
54
+ Get detailed report for a completed session
55
+
56
+ POST /emergency_stop
57
+ Emergency stop all trading sessions
58
+
59
+ πŸ§ͺ TESTING & BACKTESTING:
60
+
61
+ python main.py backtest
62
+ Run backtesting for all configured pairs
63
+
64
+ python test_api_raw.py
65
+ Test API connectivity
66
+
67
+ πŸ“Š CONFIGURED PAIRS:
68
+ β€’ BTCUSDT
69
+ β€’ ETHUSDT
70
+ β€’ SOLUSDT
71
+
72
+ βš™οΈ TRADING PARAMETERS:
73
+ β€’ Leverage: 20x
74
+ β€’ Take Profit: 2.5%
75
+ β€’ Stop Loss: 1%
76
+ β€’ Risk per Trade: 2%
77
+ β€’ Strategy: EMA 9/21 + RSI 14 + Volume + Orderbook
78
+
79
+ πŸ“± TELEGRAM ALERTS:
80
+ Configure in .env file for trade notifications
81
+
82
+ ═══════════════════════════════════════════════════
83
+ """)
84
+
85
+ def run_backtest():
86
+ """Run backtesting mode"""
87
+ from backtester.engine import BacktestingEngine
88
+ from services.logger import log
89
+ import yaml
90
+
91
+ log("πŸ”¬ Starting backtesting mode")
92
+
93
+ settings = yaml.safe_load(open("config/settings.yaml"))
94
+ pairs = yaml.safe_load(open("config/pairs.yaml"))["pairs"]
95
+
96
+ backtester = BacktestingEngine()
97
+ results = {}
98
+
99
+ for symbol in pairs:
100
+ log(f"πŸ“Š Backtesting {symbol}...")
101
+ result = backtester.run_backtest(symbol)
102
+ results[symbol] = result
103
+
104
+ if 'error' not in result:
105
+ log(f"βœ… {symbol}: {result['total_trades']} trades, PnL: ${result['total_pnl']:.2f}, Win Rate: {result['win_rate']:.1%}")
106
+ else:
107
+ log(f"❌ {symbol}: {result['error']}")
108
+
109
+ backtester.save_results()
110
+
111
+ log("\n" + "="*50)
112
+ log("BACKTESTING REPORT")
113
+ log("="*50)
114
+
115
+ for symbol in pairs:
116
+ if symbol in results and 'error' not in results[symbol]:
117
+ report = backtester.generate_report(symbol)
118
+ print(report)
119
+
120
+ def start_api_server():
121
+ """Start the FastAPI server"""
122
+ print("πŸš€ Starting FastAPI server...")
123
+ print("πŸ“‘ Server will be available at: http://localhost:8000")
124
+ print("πŸ“– API documentation at: http://localhost:8000/docs")
125
+ print()
126
+ try:
127
+ subprocess.run([sys.executable, "api_server.py"])
128
+ except KeyboardInterrupt:
129
+ print("\nπŸ‘‹ API server stopped")
130
+
131
+ if __name__ == "__main__":
132
+ if len(sys.argv) > 1:
133
+ if sys.argv[1] == "backtest":
134
+ run_backtest()
135
+ elif sys.argv[1] == "api":
136
+ start_api_server()
137
+ elif sys.argv[1] == "help" or sys.argv[1] == "-h":
138
+ show_usage()
139
+ else:
140
+ print(f"❌ Unknown command: {sys.argv[1]}")
141
+ print("Use 'python main.py help' for available commands")
142
+ else:
143
+ show_usage()
requirements.txt ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ python-dotenv
2
+ pybit
3
+ pandas
4
+ numpy
5
+ pyyaml
6
+ requests
7
+ websockets
8
+ asyncio
9
+ ccxt
10
+ ta
11
+ plotly
12
+ matplotlib
13
+ seaborn
14
+ scikit-learn
15
+ fastapi
16
+ uvicorn
17
+ streamlit
services/logger.py ADDED
@@ -0,0 +1,226 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import logging
2
+ import logging.handlers
3
+ import json
4
+ import os
5
+ from datetime import datetime
6
+ from typing import Dict, Any, Optional
7
+ import yaml
8
+
9
+ try:
10
+ settings = yaml.safe_load(open("config/settings.yaml"))
11
+ except:
12
+ settings = {"telegram": {"enabled": False}}
13
+
14
+ class ScalperLogger:
15
+ def __init__(self):
16
+ self.setup_logging()
17
+ self.trade_logs = []
18
+ self.signal_logs = []
19
+ self.error_logs = []
20
+
21
+ def setup_logging(self):
22
+ os.makedirs("logs", exist_ok=True)
23
+ self.logger = logging.getLogger('scalper')
24
+ self.logger.setLevel(logging.DEBUG)
25
+ self.logger.handlers.clear()
26
+ console_handler = logging.StreamHandler()
27
+ console_handler.setLevel(logging.INFO)
28
+ console_formatter = logging.Formatter(
29
+ '%(asctime)s - %(levelname)s - %(message)s'
30
+ )
31
+ console_handler.setFormatter(console_formatter)
32
+ self.logger.addHandler(console_handler)
33
+ file_handler = logging.handlers.RotatingFileHandler(
34
+ 'logs/scalper.log',
35
+ maxBytes=10*1024*1024,
36
+ backupCount=5
37
+ )
38
+ file_handler.setLevel(logging.DEBUG)
39
+ file_formatter = logging.Formatter(
40
+ '%(asctime)s - %(name)s - %(levelname)s - %(funcName)s:%(lineno)d - %(message)s'
41
+ )
42
+ file_handler.setFormatter(file_formatter)
43
+ self.logger.addHandler(file_handler)
44
+ trade_handler = logging.handlers.RotatingFileHandler(
45
+ 'logs/trades.log',
46
+ maxBytes=5*1024*1024,
47
+ backupCount=3
48
+ )
49
+ trade_handler.setLevel(logging.INFO)
50
+ trade_formatter = logging.Formatter(
51
+ '%(asctime)s - TRADE - %(message)s'
52
+ )
53
+ trade_handler.setFormatter(trade_formatter)
54
+ trade_handler.addFilter(self._trade_filter)
55
+ self.logger.addHandler(trade_handler)
56
+ error_handler = logging.handlers.RotatingFileHandler(
57
+ 'logs/errors.log',
58
+ maxBytes=5*1024*1024,
59
+ backupCount=3
60
+ )
61
+ error_handler.setLevel(logging.ERROR)
62
+ error_formatter = logging.Formatter(
63
+ '%(asctime)s - ERROR - %(message)s'
64
+ )
65
+ error_handler.setFormatter(error_formatter)
66
+ self.logger.addHandler(error_handler)
67
+
68
+ def _trade_filter(self, record):
69
+ return 'TRADE' in record.getMessage() or 'SIGNAL' in record.getMessage()
70
+
71
+ def log_signal(self, symbol: str, signal: str, confidence: float, price: float,
72
+ strategy_details: Optional[Dict[str, Any]] = None):
73
+ try:
74
+ signal_data = {
75
+ 'timestamp': datetime.now().isoformat(),
76
+ 'symbol': symbol,
77
+ 'signal': signal,
78
+ 'confidence': confidence,
79
+ 'price': price,
80
+ 'strategy_details': strategy_details or {}
81
+ }
82
+ self.signal_logs.append(signal_data)
83
+ if len(self.signal_logs) > 1000:
84
+ self.signal_logs = self.signal_logs[-1000:]
85
+ self._save_signals_to_file()
86
+ self.logger.info(f"SIGNAL - {symbol}: {signal} (conf: {confidence:.2f}) at {price}")
87
+ except Exception as e:
88
+ self.logger.error(f"Error logging signal: {e}")
89
+
90
+ def log_trade(self, symbol: str, side: str, qty: float, price: float,
91
+ order_type: str = "MARKET", pnl: Optional[float] = None,
92
+ reason: str = "signal"):
93
+ try:
94
+ trade_data = {
95
+ 'timestamp': datetime.now().isoformat(),
96
+ 'symbol': symbol,
97
+ 'side': side,
98
+ 'quantity': qty,
99
+ 'price': price,
100
+ 'order_type': order_type,
101
+ 'pnl': pnl,
102
+ 'reason': reason
103
+ }
104
+ self.trade_logs.append(trade_data)
105
+ if len(self.trade_logs) > 1000:
106
+ self.trade_logs = self.trade_logs[-1000:]
107
+ self._save_trades_to_file()
108
+ pnl_str = f" (PnL: {pnl:.2f})" if pnl is not None else ""
109
+ self.logger.info(f"TRADE - {symbol}: {side} {qty} at {price}{pnl_str}")
110
+ except Exception as e:
111
+ self.logger.error(f"Error logging trade: {e}")
112
+
113
+ def log_error(self, error_type: str, message: str, details: Optional[Dict[str, Any]] = None):
114
+ try:
115
+ error_data = {
116
+ 'timestamp': datetime.now().isoformat(),
117
+ 'type': error_type,
118
+ 'message': message,
119
+ 'details': details or {}
120
+ }
121
+ self.error_logs.append(error_data)
122
+ if len(self.error_logs) > 500:
123
+ self.error_logs = self.error_logs[-500:]
124
+ self._save_errors_to_file()
125
+ self.logger.error(f"{error_type.upper()}: {message}")
126
+ except Exception as e:
127
+ print(f"Critical logging error: {e}")
128
+
129
+ def log_performance(self, symbol: str, period: str, metrics: Dict[str, Any]):
130
+ try:
131
+ perf_data = {
132
+ 'timestamp': datetime.now().isoformat(),
133
+ 'symbol': symbol,
134
+ 'period': period,
135
+ 'metrics': metrics
136
+ }
137
+ self._save_performance_to_file(perf_data)
138
+ metrics_str = ", ".join([f"{k}: {v:.2f}" if isinstance(v, (int, float)) else f"{k}: {v}"
139
+ for k, v in metrics.items()])
140
+ self.logger.info(f"PERFORMANCE - {symbol} ({period}): {metrics_str}")
141
+ except Exception as e:
142
+ self.logger.error(f"Error logging performance: {e}")
143
+
144
+ def _save_signals_to_file(self):
145
+ try:
146
+ with open('logs/signals.json', 'w') as f:
147
+ json.dump(self.signal_logs, f, indent=2)
148
+ except Exception as e:
149
+ self.logger.error(f"Error saving signals: {e}")
150
+
151
+ def _save_trades_to_file(self):
152
+ try:
153
+ with open('logs/trades.json', 'w') as f:
154
+ json.dump(self.trade_logs, f, indent=2)
155
+ except Exception as e:
156
+ self.logger.error(f"Error saving trades: {e}")
157
+
158
+ def _save_errors_to_file(self):
159
+ try:
160
+ with open('logs/errors.json', 'w') as f:
161
+ json.dump(self.error_logs, f, indent=2)
162
+ except Exception as e:
163
+ print(f"Error saving errors: {e}")
164
+
165
+ def _save_performance_to_file(self, perf_data: Dict[str, Any]):
166
+ try:
167
+ with open('logs/performance.jsonl', 'a') as f:
168
+ json.dump(perf_data, f)
169
+ f.write('\n')
170
+ except Exception as e:
171
+ self.logger.error(f"Error saving performance: {e}")
172
+
173
+ def get_recent_signals(self, limit: int = 50) -> list:
174
+ return self.signal_logs[-limit:]
175
+
176
+ def get_recent_trades(self, limit: int = 50) -> list:
177
+ return self.trade_logs[-limit:]
178
+
179
+ def get_error_summary(self) -> Dict[str, int]:
180
+ summary = {}
181
+ for error in self.error_logs:
182
+ error_type = error.get('type', 'unknown')
183
+ summary[error_type] = summary.get(error_type, 0) + 1
184
+ return summary
185
+
186
+ def get_trade_statistics(self) -> Dict[str, Any]:
187
+ if not self.trade_logs:
188
+ return {'total_trades': 0, 'win_rate': 0.0, 'total_pnl': 0.0}
189
+ total_trades = len(self.trade_logs)
190
+ winning_trades = sum(1 for trade in self.trade_logs if trade.get('pnl', 0) > 0)
191
+ total_pnl = sum(trade.get('pnl', 0) for trade in self.trade_logs)
192
+ return {
193
+ 'total_trades': total_trades,
194
+ 'win_rate': winning_trades / total_trades if total_trades > 0 else 0.0,
195
+ 'total_pnl': total_pnl,
196
+ 'avg_pnl_per_trade': total_pnl / total_trades if total_trades > 0 else 0.0
197
+ }
198
+
199
+ logger_instance = ScalperLogger()
200
+
201
+ def log(message: str, level: str = "info"):
202
+ if level.lower() == "debug":
203
+ logger_instance.logger.debug(message)
204
+ elif level.lower() == "info":
205
+ logger_instance.logger.info(message)
206
+ elif level.lower() == "warning":
207
+ logger_instance.logger.warning(message)
208
+ elif level.lower() == "error":
209
+ logger_instance.logger.error(message)
210
+ elif level.lower() == "critical":
211
+ logger_instance.logger.critical(message)
212
+
213
+ def log_signal(symbol: str, signal: str, confidence: float, price: float,
214
+ strategy_details: Optional[Dict[str, Any]] = None):
215
+ logger_instance.log_signal(symbol, signal, confidence, price, strategy_details)
216
+
217
+ def log_trade(symbol: str, side: str, qty: float, price: float,
218
+ order_type: str = "MARKET", pnl: Optional[float] = None,
219
+ reason: str = "signal"):
220
+ logger_instance.log_trade(symbol, side, qty, price, order_type, pnl, reason)
221
+
222
+ def log_error(error_type: str, message: str, details: Optional[Dict[str, Any]] = None):
223
+ logger_instance.log_error(error_type, message, details)
224
+
225
+ def log_performance(symbol: str, period: str, metrics: Dict[str, Any]):
226
+ logger_instance.log_performance(symbol, period, metrics)
services/telegram.py ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import requests
3
+ from dotenv import load_dotenv
4
+ import yaml
5
+
6
+ load_dotenv()
7
+ settings = yaml.safe_load(open("config/settings.yaml"))
8
+
9
+ BOT_TOKEN = os.getenv("TELEGRAM_BOT_TOKEN")
10
+ CHAT_ID = os.getenv("TELEGRAM_CHAT_ID")
11
+
12
+ def send_telegram(msg):
13
+ if not settings["telegram"]["enabled"]:
14
+ return
15
+
16
+ if not BOT_TOKEN or not CHAT_ID:
17
+ print("[WARNING] Telegram not configured.")
18
+ return
19
+
20
+ url = f"https://api.telegram.org/bot{BOT_TOKEN}/sendMessage"
21
+ requests.post(url, data={"chat_id": CHAT_ID, "text": msg})
test/MAINNET_STATUS.md ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # πŸš€ MAINNET CONFIGURATION COMPLETE
2
+
3
+ βœ… API Connection: WORKING
4
+ βœ… Account Balance: ACCESSIBLE
5
+ βœ… Position Monitoring: WORKING
6
+ βœ… Order Monitoring: WORKING
7
+ ⚠️ Order Creation: BLOCKED (Symbol whitelisting)
8
+
9
+ The bot is ready for monitoring and analysis on mainnet!
10
+ For live trading, BTCUSDT needs to be whitelisted for your API key.
11
+
12
+ Current .env configuration:
13
+ - BYBIT_TESTNET=false (Mainnet enabled)
14
+ - API credentials loaded
15
+
16
+ Ready to run: python3 main.py
test/README.md ADDED
@@ -0,0 +1,481 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Bybit Scalping Bot πŸ€–
2
+
3
+ A production-ready cryptocurrency scalping bot that trades BTCUSDT, ETHUSDT, and SOLUSDT using multiple sophisticated strategies with 20x leverage and automated risk management.
4
+
5
+ ![Python](https://img.shields.io/badge/python-3.8+-blue.svg)
6
+ ![License](https://img.shields.io/badge/license-MIT-green.svg)
7
+ ![Status](https://img.shields.io/badge/status-production--ready-brightgreen.svg)
8
+
9
+ ## ⚑ Features
10
+
11
+ - **Multi-Strategy Trading**: Three advanced scalping strategies (EMA Momentum, Breakout, Pullback)
12
+ - **20x Leverage**: Configurable leverage with automatic position sizing
13
+ - **Automated TP/SL**: Take profit at 2.5%, stop loss at 1%
14
+ - **Real-Time Data**: WebSocket streaming for ultra-fast signal generation
15
+ - **Risk Management**: Dynamic position sizing, daily loss limits, volatility filters
16
+ - **Backtesting Engine**: Historical performance analysis and parameter optimization
17
+ - **Comprehensive Logging**: Detailed trade logs, performance metrics, error tracking
18
+ - **Telegram Notifications**: Real-time trade alerts and bot status updates
19
+ - **Production Ready**: Error handling, reconnection logic, graceful shutdown
20
+
21
+ ## πŸš€ Quick Start
22
+
23
+ ### 1. Environment Setup
24
+
25
+ ```bash
26
+ # Clone the repository
27
+ git clone <repository-url>
28
+ cd scalper
29
+
30
+ # Install dependencies
31
+ pip install -r requirements.txt
32
+
33
+ # Copy environment template
34
+ cp .env.example .env
35
+ ```
36
+
37
+ ### 2. API Configuration
38
+
39
+ 1. Create a Bybit account at [bybit.com](https://bybit.com)
40
+ 2. Generate API keys in Account > API Management
41
+ 3. **Required Permissions:**
42
+ - βœ… **Unified Trading Account** β†’ Read & Trade
43
+ - βœ… **USDC Derivatives** β†’ Read & Trade
44
+ - βœ… **Spot** β†’ Read & Trade
45
+ 4. **Important**: Add your IP address to the whitelist
46
+
47
+ Edit `.env` file:
48
+ ```env
49
+ BYBIT_API_KEY=your_api_key_here
50
+ BYBIT_API_SECRET=your_api_secret_here
51
+ BYBIT_TESTNET=false # Use false for mainnet
52
+ TELEGRAM_BOT_TOKEN=your_telegram_bot_token_here # Optional
53
+ TELEGRAM_CHAT_ID=your_chat_id_here # Optional
54
+ ```
55
+
56
+ ### 3. Start API Server
57
+
58
+ ```bash
59
+ # Start the FastAPI control server
60
+ python3 api_server.py
61
+ ```
62
+
63
+ Server will be available at: **http://localhost:8000**
64
+
65
+ ### 4. Control Trading via API
66
+
67
+ #### Start Trading for BTC (18 hours default):
68
+ ```bash
69
+ curl -X POST http://localhost:8000/start/BTCUSDT
70
+ ```
71
+
72
+ #### Start Trading for ETH (custom duration):
73
+ ```bash
74
+ curl -X POST "http://localhost:8000/start/ETHUSDT?duration_hours=24"
75
+ ```
76
+
77
+ #### Check Bot Status:
78
+ ```bash
79
+ curl http://localhost:8000/status
80
+ ```
81
+
82
+ #### Stop Trading:
83
+ ```bash
84
+ curl -X POST http://localhost:8000/stop/BTCUSDT
85
+ ```
86
+
87
+ ### 5. Run Backtest
88
+
89
+ ```bash
90
+ python3 main.py backtest
91
+ ```
92
+
93
+ ## πŸ“‘ FastAPI Control Interface
94
+
95
+ The bot uses FastAPI for remote control, allowing you to start/stop trading sessions for individual pairs.
96
+
97
+ ### API Endpoints
98
+
99
+ #### `GET /status`
100
+ Get current bot status and active sessions.
101
+ ```bash
102
+ curl http://localhost:8000/status
103
+ ```
104
+
105
+ #### `POST /start/{symbol}`
106
+ Start trading session for a specific symbol.
107
+ ```bash
108
+ # Default 18 hours
109
+ curl -X POST http://localhost:8000/start/BTCUSDT
110
+
111
+ # Custom duration
112
+ curl -X POST "http://localhost:8000/start/ETHUSDT?duration_hours=24"
113
+
114
+ # Limited trades
115
+ curl -X POST "http://localhost:8000/start/SOLUSDT?duration_hours=12&max_trades=50"
116
+ ```
117
+
118
+ #### `POST /stop/{symbol}`
119
+ Stop trading session for a specific symbol.
120
+ ```bash
121
+ curl -X POST http://localhost:8000/stop/BTCUSDT
122
+ ```
123
+
124
+ #### `GET /sessions`
125
+ Get all trading sessions (active and completed).
126
+ ```bash
127
+ curl http://localhost:8000/sessions
128
+ ```
129
+
130
+ #### `GET /report/{session_id}`
131
+ Get detailed report for a completed session.
132
+ ```bash
133
+ curl http://localhost:8000/report/BTCUSDT_1703123456
134
+ ```
135
+
136
+ #### `POST /start_all`
137
+ Start trading sessions for ALL configured pairs simultaneously.
138
+ ```bash
139
+ # Start all pairs (BTC, ETH, SOL) for 18 hours
140
+ curl -X POST "http://localhost:8000/start_all"
141
+
142
+ # Custom duration for all pairs
143
+ curl -X POST "http://localhost:8000/start_all?duration_hours=24"
144
+ ```
145
+
146
+ #### `POST /stop_all`
147
+ Stop trading sessions for ALL pairs.
148
+ ```bash
149
+ curl -X POST http://localhost:8000/stop_all
150
+ ```
151
+
152
+ #### `GET /logs/analysis`
153
+ Get recent analysis logs (strategy signals, indicator values).
154
+ ```bash
155
+ curl "http://localhost:8000/logs/analysis"
156
+ curl "http://localhost:8000/logs/analysis?lines=100"
157
+ ```
158
+
159
+ #### `GET /logs/live`
160
+ Get recent live logs (all bot activities).
161
+ ```bash
162
+ curl "http://localhost:8000/logs/live"
163
+ curl "http://localhost:8000/logs/live?lines=50"
164
+ ```
165
+
166
+ #### `GET /analysis/status`
167
+ Get real-time analysis status for all active sessions.
168
+ ```bash
169
+ curl "http://localhost:8000/analysis/status"
170
+ ```
171
+
172
+ #### `POST /emergency_stop`
173
+ Emergency stop all trading sessions.
174
+ ```bash
175
+ curl -X POST http://localhost:8000/emergency_stop
176
+ ```
177
+
178
+ ### Interactive API Documentation
179
+
180
+ When the server is running, visit: **http://localhost:8000/docs**
181
+
182
+ This provides an interactive Swagger UI to test all endpoints.
183
+
184
+ ### Example Workflow
185
+
186
+ ```bash
187
+ # 1. Start API server
188
+ python3 api_server.py
189
+
190
+ # 2. Start BTC trading for 18 hours
191
+ curl -X POST http://localhost:8000/start/BTCUSDT
192
+
193
+ # 3. Check status
194
+ curl http://localhost:8000/status
195
+
196
+ # 4. Start ETH trading for 24 hours
197
+ curl -X POST "http://localhost:8000/start/ETHUSDT?duration_hours=24"
198
+
199
+ # 5. Stop BTC trading
200
+ curl -X POST http://localhost:8000/stop/BTCUSDT
201
+
202
+ # 6. Get final reports
203
+ curl http://localhost:8000/sessions
204
+ ```
205
+
206
+ ## πŸ“Š Trading Strategies
207
+
208
+ ### 1. EMA Momentum Scalping
209
+ - **Entry**: EMA9 crosses above EMA21 in bullish direction
210
+ - **Confirmation**: RSI oversold (<35) + bid dominance in orderbook
211
+ - **Exit**: 2.5% profit or 1% stop loss
212
+
213
+ ### 2. Breakout Scalper
214
+ - **Entry**: Price breaks above recent highs with volume spike
215
+ - **Confirmation**: Spread contraction + orderbook imbalance
216
+ - **Exit**: Time-based (5-15 min) or TP/SL hit
217
+
218
+ ### 3. Pullback Scalper
219
+ - **Entry**: Price retraces to EMA21 in trending market
220
+ - **Confirmation**: Volume decreases on pullback, increases on continuation
221
+ - **Exit**: Trend continuation signal or timeout
222
+
223
+ ## πŸ—οΈ Architecture
224
+
225
+ ```
226
+ scalper/
227
+ β”œβ”€β”€ main.py # Entry point
228
+ β”œβ”€β”€ config/
229
+ β”‚ β”œβ”€β”€ settings.yaml # Trading parameters
230
+ β”‚ └── pairs.yaml # Trading pairs
231
+ β”œβ”€β”€ core/
232
+ β”‚ β”œβ”€β”€ exchange.py # Bybit API wrapper
233
+ β”‚ β”œβ”€β”€ strategy.py # Trading strategies
234
+ β”‚ β”œβ”€β”€ risk.py # Risk management
235
+ β”‚ β”œβ”€β”€ data_engine.py # Data storage & indicators
236
+ β”‚ β”œβ”€β”€ trade_monitor.py # Trade monitoring loop
237
+ β”‚ └── websockets.py # Real-time data streaming
238
+ β”œβ”€β”€ services/
239
+ β”‚ β”œβ”€β”€ logger.py # Logging system
240
+ β”‚ └── telegram.py # Telegram notifications
241
+ β”œβ”€β”€ backtester/
242
+ β”‚ └── engine.py # Backtesting engine
243
+ β”œβ”€β”€ logs/ # Log files
244
+ β”œβ”€β”€ backtest_results/ # Backtest outputs
245
+ └── requirements.txt # Dependencies
246
+ ```
247
+
248
+ ## βš™οΈ Configuration
249
+
250
+ ### Trading Parameters
251
+
252
+ | Parameter | Default | Description |
253
+ |-----------|---------|-------------|
254
+ | `leverage` | 20 | Trading leverage |
255
+ | `tp_percent` | 0.025 | Take profit percentage |
256
+ | `sl_percent` | 0.01 | Stop loss percentage |
257
+ | `risk_per_trade` | 0.02 | Risk per trade (% of balance) |
258
+
259
+ ### Strategy Parameters
260
+
261
+ | Parameter | Default | Description |
262
+ |-----------|---------|-------------|
263
+ | `interval` | "1" | Candle interval (minutes) |
264
+ | `rsi_period` | 14 | RSI calculation period |
265
+ | `ema_fast` | 9 | Fast EMA period |
266
+ | `ema_slow` | 21 | Slow EMA period |
267
+
268
+ ## πŸ”¬ Backtesting
269
+
270
+ Run comprehensive backtests to evaluate strategy performance:
271
+
272
+ ```bash
273
+ python main.py backtest
274
+ ```
275
+
276
+ ### Backtest Metrics
277
+ - **Win Rate**: Percentage of profitable trades
278
+ - **Profit Factor**: Gross profit / Gross loss
279
+ - **Max Drawdown**: Largest peak-to-valley decline
280
+ - **Sharpe Ratio**: Risk-adjusted returns
281
+ - **Average Trade Duration**: Typical trade holding time
282
+
283
+ ### Parameter Optimization
284
+
285
+ The backtester includes grid search optimization for:
286
+ - EMA periods
287
+ - RSI thresholds
288
+ - Risk percentages
289
+ - Timeframe settings
290
+
291
+ ## πŸ“ˆ Risk Management
292
+
293
+ ### Safety Features
294
+ - **Daily Loss Limits**: Automatic stop when daily loss exceeds threshold
295
+ - **Volatility Filters**: Skip trading during high volatility periods
296
+ - **Spread Filters**: Avoid wide spreads that increase slippage
297
+ - **Position Limits**: Maximum one position per symbol
298
+ - **Emergency Stop**: Manual override capability
299
+
300
+ ### Position Sizing
301
+ ```python
302
+ risk_amount = balance * risk_per_trade
303
+ position_size = risk_amount / (sl_distance * leverage)
304
+ ```
305
+
306
+ ## 🌐 WebSocket Integration
307
+
308
+ Real-time data streams for ultra-fast execution:
309
+ - **Tickers**: Price updates every 100ms
310
+ - **Klines**: 1-minute and 5-minute candles
311
+ - **Orderbook**: Top 25 bids/asks with depth
312
+ - **Trades**: Recent market trades
313
+ - **Auto-Reconnect**: Handles connection drops gracefully
314
+
315
+ ## πŸ“Š Monitoring & Logging
316
+
317
+ ### Log Files
318
+ - `logs/scalper.log`: General application logs
319
+ - `logs/trades.log`: Trade execution logs
320
+ - `logs/errors.log`: Error tracking
321
+ - `logs/signals.json`: Trading signals
322
+ - `logs/performance.jsonl`: Performance metrics
323
+
324
+ ### Telegram Alerts
325
+ Configure for real-time notifications:
326
+ - Trade executions
327
+ - Strategy signals
328
+ - Error alerts
329
+ - Daily performance summaries
330
+
331
+ ## πŸš€ Deployment
332
+
333
+ ### Local Machine
334
+ ```bash
335
+ # Run in background
336
+ nohup python main.py &
337
+ ```
338
+
339
+ ### VPS Deployment (Recommended)
340
+ ```bash
341
+ # Install dependencies
342
+ sudo apt update
343
+ sudo apt install python3 python3-pip tmux
344
+
345
+ # Clone and setup
346
+ git clone <repository-url>
347
+ cd scalper
348
+ pip install -r requirements.txt
349
+
350
+ # Run with process manager
351
+ tmux new -s scalper
352
+ python main.py
353
+ # Ctrl+B, D to detach
354
+ ```
355
+
356
+ ### Process Manager (PM2)
357
+ ```bash
358
+ npm install -g pm2
359
+ pm2 start main.py --name scalper
360
+ pm2 startup
361
+ pm2 save
362
+ ```
363
+
364
+ ## πŸ”§ Troubleshooting
365
+
366
+ ### Common Issues
367
+
368
+ **API Connection Failed**
369
+ ```bash
370
+ # Check API keys in .env
371
+ cat .env
372
+ # Verify testnet setting
373
+ # Check Bybit API status
374
+ ```
375
+
376
+ **WebSocket Disconnection**
377
+ - Automatic reconnection is built-in
378
+ - Check internet connection
379
+ - Verify Bybit service status
380
+
381
+ **No Trading Signals**
382
+ ```bash
383
+ # Check market conditions
384
+ python -c "from core.data_engine import DataEngine; de = DataEngine(); print(de.get_buffer_status())"
385
+ # Verify strategy parameters
386
+ # Check volatility filters
387
+ ```
388
+
389
+ **Position Not Opening**
390
+ - Verify account balance
391
+ - Check risk management settings
392
+ - Review API permissions
393
+
394
+ ### Debug Mode
395
+ ```bash
396
+ # Enable debug logging
397
+ export LOG_LEVEL=DEBUG
398
+ python main.py
399
+ ```
400
+
401
+ ## πŸ“ˆ Performance Optimization
402
+
403
+ ### Strategy Tuning
404
+ 1. Run backtests with different parameters
405
+ 2. Optimize for specific market conditions
406
+ 3. Adjust risk parameters based on drawdown
407
+
408
+ ### Hardware Requirements
409
+ - **CPU**: 2+ cores recommended
410
+ - **RAM**: 2-4 GB sufficient
411
+ - **Network**: Stable internet connection
412
+ - **Storage**: 1GB for logs and data
413
+
414
+ ## 🀝 Contributing
415
+
416
+ 1. Fork the repository
417
+ 2. Create a feature branch
418
+ 3. Add tests for new functionality
419
+ 4. Submit a pull request
420
+
421
+ ## πŸ“œ License
422
+
423
+ MIT License - see [LICENSE](LICENSE) file for details.
424
+
425
+ ## ⚠️ Disclaimer
426
+
427
+ **This software is for educational and research purposes only. Trading cryptocurrencies involves substantial risk of loss and is not suitable for every investor. Past performance does not guarantee future results. Please test thoroughly and use at your own risk.**
428
+
429
+ ### Risk Warnings
430
+ - **Leverage Trading**: 20x leverage can amplify both gains and losses
431
+ - **Market Volatility**: Crypto markets can be highly volatile
432
+ - **Technical Risks**: Software bugs, internet outages, API issues
433
+ - **Financial Risk**: Never invest more than you can afford to lose
434
+
435
+ ## πŸ†˜ Support
436
+
437
+ - **Issues**: Open a GitHub issue
438
+ - **Documentation**: Check this README and inline code comments
439
+ - **Community**: Join crypto trading communities for general advice
440
+
441
+ ---
442
+
443
+ ## 🌐 **Hugging Face Deployment**
444
+
445
+ ### **Deploy to Hugging Face Spaces**
446
+
447
+ 1. **Create Space**: Go to [hf.co/spaces](https://hf.co/spaces) β†’ "Create new Space"
448
+ - **Name**: `your-scalping-bot`
449
+ - **SDK**: `Docker`
450
+ - **Storage**: `Small`
451
+
452
+ 2. **Repository Setup**:
453
+ ```bash
454
+ # Push your code to GitHub
455
+ git add .
456
+ git commit -m "Scalping bot deployment"
457
+ git push origin main
458
+ ```
459
+
460
+ 3. **Connect Repository**: In Space settings β†’ "Connect Repository"
461
+ - Enter your GitHub URL
462
+ - Branch: `main`
463
+
464
+ 4. **Public URL**: You'll get a URL like:
465
+ ```
466
+ https://yourusername-your-scalping-bot.hf.space
467
+ ```
468
+ **This is your public IP for remote access!**
469
+
470
+ 5. **Configure API Keys**: Use the web interface to set your Bybit credentials
471
+
472
+ ### **Hugging Face Features**
473
+ - 🌐 **Public web dashboard** with real-time analysis
474
+ - πŸ“Š **Interactive charts** and performance metrics
475
+ - πŸŽ›οΈ **One-click trading** controls
476
+ - πŸ“± **Mobile-friendly** interface
477
+ - πŸ”„ **Auto-scaling** and uptime monitoring
478
+
479
+ ---
480
+
481
+ **Happy Trading! πŸš€**
test/get_chat_id.py ADDED
@@ -0,0 +1,124 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+ """
3
+ Get Telegram Chat ID for bot notifications
4
+ Run this script, then send a message to your bot
5
+ """
6
+
7
+ import requests
8
+ import time
9
+
10
+ # Your bot token
11
+ BOT_TOKEN = "8555333979:AAH_oCYvbXEt6IQ0-qbFdb9kSjdqpyIJcqA"
12
+ BASE_URL = f"https://api.telegram.org/bot{BOT_TOKEN}"
13
+
14
+ def get_bot_info():
15
+ """Get bot information"""
16
+ try:
17
+ response = requests.get(f"{BASE_URL}/getMe")
18
+ if response.status_code == 200:
19
+ bot_info = response.json()
20
+ if bot_info['ok']:
21
+ print("πŸ€– Bot Information:")
22
+ print(f" Name: {bot_info['result']['first_name']}")
23
+ print(f" Username: @{bot_info['result']['username']}")
24
+ print(f" Can read messages: {bot_info['result']['can_read_all_group_messages']}")
25
+ return True
26
+ print(f"❌ Failed to get bot info: {response.text}")
27
+ return False
28
+ except Exception as e:
29
+ print(f"❌ Error: {e}")
30
+ return False
31
+
32
+ def get_updates():
33
+ """Get recent updates (messages) to extract chat ID"""
34
+ try:
35
+ response = requests.get(f"{BASE_URL}/getUpdates", timeout=30)
36
+ if response.status_code == 200:
37
+ updates = response.json()
38
+ if updates['ok'] and updates['result']:
39
+ print("\nπŸ“¨ Recent Messages:")
40
+ for update in updates['result'][-5:]: # Show last 5 messages
41
+ if 'message' in update:
42
+ message = update['message']
43
+ chat = message['chat']
44
+ from_user = message.get('from', {})
45
+
46
+ print(f"\nπŸ’¬ Message from: {from_user.get('first_name', 'Unknown')}")
47
+ print(f" Chat ID: {chat['id']}")
48
+ print(f" Chat Type: {chat['type']}")
49
+ print(f" Message: {message.get('text', 'N/A')}")
50
+ print(f" Time: {time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(message['date']))}")
51
+
52
+ if chat['type'] == 'private':
53
+ print(f"\n🎯 YOUR CHAT ID: {chat['id']}")
54
+ print(" Use this in your .env file as TELEGRAM_CHAT_ID")
55
+ return chat['id']
56
+ print("\nπŸ’‘ No recent messages found. Send a message to your bot and run this again.")
57
+ return None
58
+ else:
59
+ print("\nπŸ’‘ No messages received yet. Please:")
60
+ print(" 1. Open Telegram")
61
+ print(" 2. Find your bot: Search for the username shown above")
62
+ print(" 3. Send any message to the bot")
63
+ print(" 4. Run this script again")
64
+ return None
65
+ else:
66
+ print(f"❌ Failed to get updates: {response.text}")
67
+ return None
68
+ except Exception as e:
69
+ print(f"❌ Error getting updates: {e}")
70
+ return None
71
+
72
+ def send_test_message(chat_id):
73
+ """Send a test message to confirm chat ID works"""
74
+ try:
75
+ message = "βœ… Telegram integration test successful! Your chat ID is working."
76
+ data = {
77
+ 'chat_id': chat_id,
78
+ 'text': message
79
+ }
80
+ response = requests.post(f"{BASE_URL}/sendMessage", data=data)
81
+ if response.status_code == 200:
82
+ print("\nπŸ“€ Test message sent! Check your Telegram.")
83
+ return True
84
+ else:
85
+ print(f"❌ Failed to send test message: {response.text}")
86
+ return False
87
+ except Exception as e:
88
+ print(f"❌ Error sending test message: {e}")
89
+ return False
90
+
91
+ def main():
92
+ print("πŸ” Telegram Chat ID Finder")
93
+ print("=" * 40)
94
+
95
+ if not get_bot_info():
96
+ print("❌ Bot token is invalid. Please check your token.")
97
+ return
98
+
99
+ print("\n⏳ Waiting for messages... (you have 30 seconds)")
100
+ print("πŸ“± Please send a message to your bot now...")
101
+
102
+ chat_id = get_updates()
103
+
104
+ if chat_id:
105
+ print(f"\nπŸŽ‰ Found your Chat ID: {chat_id}")
106
+
107
+ if send_test_message(chat_id):
108
+ print("\nβœ… Setup complete!")
109
+ print("\nπŸ“ Add this to your .env file:")
110
+ print(f"TELEGRAM_BOT_TOKEN={BOT_TOKEN}")
111
+ print(f"TELEGRAM_CHAT_ID={chat_id}")
112
+
113
+ print("\nπŸ“„ Or update your existing .env:")
114
+ print("TELEGRAM_CHAT_ID=your_chat_id_here")
115
+ print(f" ↑ replace with: {chat_id}")
116
+ else:
117
+ print("\n⚠️ Chat ID found but test message failed.")
118
+ print(" You can still use the chat ID, but double-check your setup.")
119
+ else:
120
+ print("\n❌ No chat ID found.")
121
+ print(" Make sure to send a message to your bot and run this script again.")
122
+
123
+ if __name__ == "__main__":
124
+ main()
test/huggingface_README.md ADDED
@@ -0,0 +1,318 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # πŸš€ Deploy Scalping Bot on Hugging Face Spaces
2
+
3
+ ## Prerequisites
4
+
5
+ 1. **Hugging Face Account**: Create account at [huggingface.co](https://huggingface.co)
6
+ 2. **API Credentials**: Your Bybit API keys ready
7
+ 3. **Git Repository**: Push your code to GitHub/GitLab
8
+
9
+ ## Step 1: Create Hugging Face Space
10
+
11
+ 1. Go to [huggingface.co/spaces](https://huggingface.co/spaces)
12
+ 2. Click "Create new Space"
13
+ 3. Choose:
14
+ - **Space name**: `your-scalping-bot`
15
+ - **License**: Apache-2.0
16
+ - **SDK**: **Docker** (for full control)
17
+ - **Storage**: Small (sufficient)
18
+
19
+ ## Step 2: Repository Structure
20
+
21
+ Your repository should look like:
22
+ ```
23
+ your-scalping-bot/
24
+ β”œβ”€β”€ app.py # Streamlit/FastAPI app
25
+ β”œβ”€β”€ requirements.txt # Dependencies
26
+ β”œβ”€β”€ packages.txt # System packages (if needed)
27
+ β”œβ”€β”€ config/
28
+ β”‚ β”œβ”€β”€ settings.yaml
29
+ β”‚ └── pairs.yaml
30
+ β”œβ”€β”€ core/
31
+ β”‚ β”œβ”€β”€ exchange.py
32
+ β”‚ β”œβ”€β”€ strategy.py
33
+ β”‚ └── ...
34
+ β”œβ”€β”€ services/
35
+ β”‚ └── ...
36
+ └── README.md
37
+ ```
38
+
39
+ ## Step 3: Create app.py
40
+
41
+ ```python
42
+ import streamlit as st
43
+ import subprocess
44
+ import os
45
+ import signal
46
+ import time
47
+ from threading import Thread
48
+ import requests
49
+
50
+ # Set page config
51
+ st.set_page_config(
52
+ page_title="Scalping Bot Control",
53
+ page_icon="πŸ€–",
54
+ layout="wide"
55
+ )
56
+
57
+ st.title("πŸ€– Bybit Scalping Bot Control Panel")
58
+
59
+ # Sidebar
60
+ st.sidebar.header("βš™οΈ Configuration")
61
+
62
+ # Environment variables setup
63
+ st.sidebar.subheader("πŸ”‘ API Configuration")
64
+ bybit_key = st.sidebar.text_input("Bybit API Key", type="password")
65
+ bybit_secret = st.sidebar.text_input("Bybit API Secret", type="password")
66
+ bybit_testnet = st.sidebar.checkbox("Use Testnet", value=False)
67
+ telegram_token = st.sidebar.text_input("Telegram Bot Token (optional)")
68
+ telegram_chat = st.sidebar.text_input("Telegram Chat ID (optional)")
69
+
70
+ if st.sidebar.button("πŸ’Ύ Save Configuration"):
71
+ # Save to .env file
72
+ env_content = f"""BYBIT_API_KEY={bybit_key}
73
+ BYBIT_API_SECRET={bybit_secret}
74
+ BYBIT_TESTNET={str(bybit_testnet).lower()}
75
+ TELEGRAM_BOT_TOKEN={telegram_token}
76
+ TELEGRAM_CHAT_ID={telegram_chat}
77
+ """
78
+ with open('.env', 'w') as f:
79
+ f.write(env_content)
80
+ st.sidebar.success("Configuration saved!")
81
+
82
+ # Main content
83
+ col1, col2, col3 = st.columns(3)
84
+
85
+ with col1:
86
+ st.subheader("πŸš€ Start Trading")
87
+ symbol = st.selectbox("Symbol", ["BTCUSDT", "ETHUSDT", "SOLUSDT"])
88
+ duration = st.slider("Duration (hours)", 1, 24, 18)
89
+ max_trades = st.number_input("Max Trades (optional)", min_value=1, value=50)
90
+
91
+ if st.button("▢️ Start Trading", key="start"):
92
+ try:
93
+ response = requests.post(f"http://localhost:8000/start/{symbol}",
94
+ params={"duration_hours": duration, "max_trades": max_trades})
95
+ if response.status_code == 200:
96
+ st.success(f"βœ… Started trading {symbol} for {duration} hours")
97
+ else:
98
+ st.error(f"❌ Failed to start: {response.text}")
99
+ except Exception as e:
100
+ st.error(f"❌ Error: {e}")
101
+
102
+ with col2:
103
+ st.subheader("πŸ›‘ Stop Trading")
104
+ stop_symbol = st.selectbox("Symbol to Stop", ["BTCUSDT", "ETHUSDT", "SOLUSDT"], key="stop_select")
105
+
106
+ if st.button("⏹️ Stop Trading", key="stop"):
107
+ try:
108
+ response = requests.post(f"http://localhost:8000/stop/{stop_symbol}")
109
+ if response.status_code == 200:
110
+ st.success(f"βœ… Stopped trading {stop_symbol}")
111
+ else:
112
+ st.error(f"❌ Failed to stop: {response.text}")
113
+ except Exception as e:
114
+ st.error(f"❌ Error: {e}")
115
+
116
+ with col3:
117
+ st.subheader("🚨 Emergency")
118
+ if st.button("🚨 EMERGENCY STOP ALL", key="emergency"):
119
+ try:
120
+ response = requests.post("http://localhost:8000/emergency_stop")
121
+ if response.status_code == 200:
122
+ st.error("🚨 ALL TRADING STOPPED!")
123
+ else:
124
+ st.error(f"❌ Failed: {response.text}")
125
+ except Exception as e:
126
+ st.error(f"❌ Error: {e}")
127
+
128
+ # Status section
129
+ st.header("πŸ“Š Bot Status")
130
+
131
+ if st.button("πŸ”„ Refresh Status"):
132
+ try:
133
+ response = requests.get("http://localhost:8000/status")
134
+ if response.status_code == 200:
135
+ status = response.json()
136
+
137
+ # Overall status
138
+ if status["is_running"]:
139
+ st.success("βœ… Bot is RUNNING")
140
+ else:
141
+ st.warning("⏸️ Bot is STOPPED")
142
+
143
+ st.metric("Total P&L", f"${status['total_pnl']:.2f}")
144
+ st.metric("Trades Today", status['trades_today'])
145
+
146
+ # Active sessions
147
+ if status["active_sessions"]:
148
+ st.subheader("🎯 Active Sessions")
149
+ for session in status["active_sessions"]:
150
+ with st.expander(f"{session['symbol']} - {session['status'].upper()}"):
151
+ st.write(f"**Session ID:** {session['session_id']}")
152
+ st.write(f"**Started:** {session['start_time'][:19]}")
153
+ st.write(f"**P&L:** ${session['pnl']:.2f}")
154
+ st.write(f"**Trades:** {session['trades']}")
155
+ else:
156
+ st.info("No active sessions")
157
+
158
+ else:
159
+ st.error(f"❌ Failed to get status: {response.status_code}")
160
+ except Exception as e:
161
+ st.error(f"❌ Connection error: {e}")
162
+
163
+ # Analysis section
164
+ st.header("πŸ” Live Analysis")
165
+
166
+ if st.button("πŸ“Š Refresh Analysis"):
167
+ try:
168
+ response = requests.get("http://localhost:8000/analysis/status")
169
+ if response.status_code == 200:
170
+ analysis = response.json()
171
+
172
+ for symbol, data in analysis["analysis_status"].items():
173
+ with st.expander(f"πŸ“ˆ {symbol} Analysis"):
174
+ col1, col2 = st.columns(2)
175
+
176
+ with col1:
177
+ st.metric("Current Price", f"${data['current_price']:.2f}" if data['current_price'] else "N/A")
178
+
179
+ indicators = data['indicators']
180
+ st.write("**Indicators:**")
181
+ st.write(f"EMA 9: {indicators['ema_9']:.4f}" if indicators['ema_9'] else "EMA 9: N/A")
182
+ st.write(f"EMA 21: {indicators['ema_21']:.4f}" if indicators['ema_21'] else "EMA 21: N/A")
183
+ st.write(f"RSI 14: {indicators['rsi_14']:.1f}" if indicators['rsi_14'] else "RSI 14: N/A")
184
+
185
+ with col2:
186
+ conditions = data['strategy_conditions']
187
+ st.write("**Strategy Conditions:**")
188
+ st.write(f"πŸ“ˆ Trend Up: {'βœ…' if conditions['trend_up'] else '❌'}")
189
+ st.write(f"πŸ“Š RSI Valid: {'βœ…' if conditions['rsi_valid'] else '❌'}")
190
+ st.write(f"πŸ’₯ Volume Spike: {'βœ…' if conditions['volume_spike'] else '❌'}")
191
+ st.write(f"🎯 Orderbook OK: {'βœ…' if conditions['orderbook_aligned'] else '❌'}")
192
+
193
+ all_conditions = all([conditions['trend_up'], conditions['rsi_valid'],
194
+ conditions['volume_spike'], conditions['orderbook_aligned']])
195
+
196
+ if all_conditions:
197
+ st.success("🎯 TRADE SIGNAL READY!")
198
+ else:
199
+ st.info("⏳ Waiting for conditions...")
200
+ else:
201
+ st.error(f"❌ Failed to get analysis: {response.status_code}")
202
+ except Exception as e:
203
+ st.error(f"❌ Connection error: {e}")
204
+
205
+ # Logs section
206
+ st.header("πŸ“‹ Recent Logs")
207
+
208
+ log_type = st.selectbox("Log Type", ["Live Logs", "Analysis Logs"])
209
+
210
+ if st.button("πŸ“– Refresh Logs"):
211
+ try:
212
+ if log_type == "Live Logs":
213
+ response = requests.get("http://localhost:8000/logs/live")
214
+ else:
215
+ response = requests.get("http://localhost:8000/logs/analysis")
216
+
217
+ if response.status_code == 200:
218
+ logs_data = response.json()
219
+
220
+ st.write(f"**Total {log_type}:** {logs_data['count']}")
221
+
222
+ logs_text = ""
223
+ for log_line in logs_data['logs'][-10:]: # Show last 10
224
+ logs_text += log_line
225
+
226
+ st.code(logs_text, language="text")
227
+ else:
228
+ st.error(f"❌ Failed to get logs: {response.status_code}")
229
+ except Exception as e:
230
+ st.error(f"❌ Connection error: {e}")
231
+
232
+ # Footer
233
+ st.markdown("---")
234
+ st.markdown("*πŸ€– Bybit Scalping Bot - FastAPI Control Interface*")
235
+ st.markdown("*Made with ❀️ for automated crypto trading*")
236
+ ```
237
+
238
+ ## Step 4: Create requirements.txt
239
+
240
+ ```txt
241
+ fastapi==0.104.1
242
+ uvicorn[standard]==0.24.0
243
+ streamlit==1.28.1
244
+ requests==2.31.0
245
+ python-dotenv==1.0.0
246
+ pybit==5.7.0
247
+ pyyaml==6.0.1
248
+ pandas==2.1.3
249
+ numpy==1.26.2
250
+ websockets==12.0
251
+ ```
252
+
253
+ ## Step 5: Create packages.txt (Optional)
254
+
255
+ ```
256
+ # No system packages needed
257
+ ```
258
+
259
+ ## Step 6: Deploy to Hugging Face
260
+
261
+ 1. **Push to Git**: Commit and push your code to a Git repository
262
+ 2. **Connect Space**: In your Hugging Face Space settings:
263
+ - Go to "Settings" β†’ "Connect Repository"
264
+ - Enter your repository URL
265
+ - Set branch to `main`
266
+ 3. **Auto-deploy**: Hugging Face will automatically build and deploy
267
+
268
+ ## Step 7: Access Your Bot
269
+
270
+ Once deployed, you'll get a public URL like:
271
+ ```
272
+ https://yourusername-your-scalping-bot.hf.space
273
+ ```
274
+
275
+ This will be your **public IP/URL** for accessing the bot remotely!
276
+
277
+ ## Step 8: Start the Bot
278
+
279
+ In your Hugging Face Space:
280
+ 1. βœ… Configure API keys in the sidebar
281
+ 2. βœ… Click "Start Trading" for your desired pairs
282
+ 3. βœ… Monitor analysis in real-time
283
+ 4. βœ… View logs and performance
284
+
285
+ ## πŸ”’ Security Notes
286
+
287
+ - **Never expose real API keys** in public repositories
288
+ - **Use environment variables** for sensitive data
289
+ - **Consider IP restrictions** on your Bybit API keys
290
+ - **Monitor your bot regularly** via the web interface
291
+
292
+ ## 🌐 Public Access
293
+
294
+ Your bot will be accessible worldwide via:
295
+ ```
296
+ https://[your-username]-[space-name].hf.space
297
+ ```
298
+
299
+ This serves as your **public IP address** for remote access!
300
+
301
+ ## πŸ’‘ Usage Examples
302
+
303
+ ```bash
304
+ # Direct API calls (replace with your HF Space URL)
305
+ curl -X POST "https://your-bot.hf.space/start/BTCUSDT"
306
+ curl "https://your-bot.hf.space/status"
307
+ curl "https://your-bot.hf.space/analysis/status"
308
+ ```
309
+
310
+ ## πŸŽ‰ You're Done!
311
+
312
+ Your scalping bot is now hosted on Hugging Face with:
313
+ - 🌐 **Public web interface**
314
+ - πŸ“Š **Real-time analysis dashboard**
315
+ - πŸŽ›οΈ **Remote control via API**
316
+ - πŸ“± **Mobile-friendly interface**
317
+
318
+ **Happy trading!** πŸš€πŸ€–
test/test_api.py ADDED
@@ -0,0 +1,167 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+ import os
3
+ from dotenv import load_dotenv
4
+ from pybit.unified_trading import HTTP
5
+
6
+ load_dotenv()
7
+
8
+ def test_public_endpoints():
9
+ print("Testing public API endpoints...")
10
+ try:
11
+ session = HTTP(testnet=True)
12
+
13
+ server_time = session.get_server_time()
14
+ print(f"βœ… Server time: {server_time['result']['timeSecond']}")
15
+
16
+ ticker = session.get_tickers(category="linear", symbol="BTCUSDT")
17
+ if ticker['result']['list']:
18
+ price = ticker['result']['list'][0]['lastPrice']
19
+ print(f"βœ… BTCUSDT price: ${price}")
20
+
21
+ kline = session.get_kline(
22
+ category="linear",
23
+ symbol="BTCUSDT",
24
+ interval="1",
25
+ limit=1
26
+ )
27
+ if kline['result']['list']:
28
+ print("βœ… Kline data retrieved successfully")
29
+
30
+ instruments = session.get_instruments_info(category="linear", symbol="BTCUSDT")
31
+ if instruments['result']['list']:
32
+ print("βœ… Instrument info retrieved successfully")
33
+
34
+ return True
35
+ except Exception as e:
36
+ print(f"❌ Public API test failed: {e}")
37
+ return False
38
+
39
+ def test_private_endpoints():
40
+ print("\nTesting private API endpoints...")
41
+
42
+ API_KEY = os.getenv("BYBIT_API_KEY")
43
+ API_SECRET = os.getenv("BYBIT_API_SECRET")
44
+ TESTNET = os.getenv("BYBIT_TESTNET", "true").lower() == "true"
45
+
46
+ print(f"API Key configured: {'Yes' if API_KEY else 'No'}")
47
+ print(f"API Secret configured: {'Yes' if API_SECRET else 'No'}")
48
+ print(f"Using {'TESTNET' if TESTNET else 'MAINNET'}")
49
+
50
+ if not API_KEY or not API_SECRET:
51
+ print("❌ ERROR: API credentials not found in .env file")
52
+ print("Please set BYBIT_API_KEY and BYBIT_API_SECRET in your .env file")
53
+ return False
54
+
55
+ if API_KEY == "your_api_key_here" or API_SECRET == "your_api_secret_here":
56
+ print("❌ ERROR: API credentials are still set to default placeholder values")
57
+ print("Please update .env with your actual Bybit API credentials")
58
+ return False
59
+
60
+ try:
61
+ session = HTTP(
62
+ api_key=API_KEY,
63
+ api_secret=API_SECRET,
64
+ testnet=TESTNET
65
+ )
66
+
67
+ print("βœ… HTTP client initialized with API credentials")
68
+
69
+ balance_success = False
70
+ positions_success = False
71
+ orders_success = False
72
+
73
+ try:
74
+ balance = session.get_wallet_balance(accountType="UNIFIED")
75
+ print(f"βœ… Account balance retrieved: {len(balance['result']['list'])} coins")
76
+
77
+ for coin in balance['result']['list']:
78
+ if coin['coin'] == 'USDT':
79
+ print(f" USDT Balance: {coin.get('walletBalance', '0')}")
80
+
81
+ balance_success = True
82
+
83
+ except Exception as e:
84
+ print(f"❌ Balance check failed: {e}")
85
+ print(" Trying CONTRACT account type...")
86
+
87
+ try:
88
+ balance = session.get_wallet_balance(accountType="CONTRACT")
89
+ print(f"βœ… Contract account balance retrieved: {len(balance['result']['list'])} coins")
90
+ balance_success = True
91
+ except Exception as e2:
92
+ print(f"❌ Contract balance also failed: {e2}")
93
+ print(" Common causes:")
94
+ print(" - API key lacks balance viewing permissions")
95
+ print(" - Invalid API credentials")
96
+ print(" - Account not funded on testnet")
97
+ print(" - Check API key permissions in Bybit dashboard")
98
+
99
+ try:
100
+ positions = session.get_positions(category="linear")
101
+ print(f"βœ… Positions retrieved: {len(positions['result']['list'])} positions")
102
+ positions_success = True
103
+ except Exception as e:
104
+ print(f"❌ Positions check failed: {e}")
105
+ print(" This requires 'View Positions' permission")
106
+
107
+ try:
108
+ orders = session.get_open_orders(category="linear")
109
+ print(f"βœ… Open orders retrieved: {len(orders['result']['list'])} orders")
110
+ orders_success = True
111
+ except Exception as e:
112
+ print(f"❌ Orders check failed: {e}")
113
+ print(" This requires 'View Orders' permission")
114
+
115
+ if balance_success and positions_success and orders_success:
116
+ print("πŸŽ‰ All private API endpoints working!")
117
+ return True
118
+ else:
119
+ print("⚠️ Some private API endpoints failed")
120
+ print(" For trading bot to work, you need:")
121
+ print(" - Valid API credentials")
122
+ print(" - API key with permissions: View Account Balance, View Positions, View Orders")
123
+ print(" - API key with permissions: Trade (for placing orders)")
124
+ print(" - Funded testnet account (if using testnet)")
125
+ return False
126
+
127
+ except Exception as e:
128
+ print(f"❌ Private API connection failed: {e}")
129
+ return False
130
+
131
+ def main():
132
+ print("πŸ” Bybit API Connection Test")
133
+ print("=" * 40)
134
+
135
+ public_ok = test_public_endpoints()
136
+ private_ok = test_private_endpoints()
137
+
138
+ print("\n" + "=" * 40)
139
+ print("πŸ“Š Test Results:")
140
+
141
+ if public_ok:
142
+ print("βœ… Public API: Working")
143
+ else:
144
+ print("❌ Public API: Failed")
145
+
146
+ if private_ok:
147
+ print("βœ… Private API: Working")
148
+ print("πŸŽ‰ All API tests passed! Ready for trading.")
149
+ return True
150
+ else:
151
+ print("❌ Private API: Failed")
152
+ print("\nπŸ”§ To fix private API issues:")
153
+ print("1. Go to Bybit account > API Management")
154
+ print("2. Ensure your API key has these permissions:")
155
+ print(" - 'Unified Trading Account' - Read & Trade")
156
+ print(" - 'USDC Derivatives' - Read & Trade (if using USDC)")
157
+ print(" - 'Spot' - Read & Trade (if using spot)")
158
+ print("3. Make sure your account is upgraded to Unified Trading Account")
159
+ print("4. Fund your testnet account with USDT:")
160
+ print(" - Go to Bybit testnet faucet or transfer from mainnet")
161
+ print(" - Minimum 10 USDT recommended for testing")
162
+ print("5. Verify API credentials in .env file are correct")
163
+ return False
164
+
165
+ if __name__ == "__main__":
166
+ success = main()
167
+ exit(0 if success else 1)
test/test_api_client.py ADDED
@@ -0,0 +1,81 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+ """
3
+ FastAPI Client Test - Test the scalping bot API endpoints
4
+ """
5
+
6
+ import requests
7
+ import time
8
+ import json
9
+
10
+ BASE_URL = "http://localhost:8000"
11
+
12
+ def test_endpoint(method, endpoint, data=None, params=None):
13
+ """Test an API endpoint"""
14
+ try:
15
+ url = f"{BASE_URL}{endpoint}"
16
+
17
+ if method == "GET":
18
+ response = requests.get(url, params=params)
19
+ elif method == "POST":
20
+ response = requests.post(url, json=data, params=params)
21
+ else:
22
+ print(f"❌ Unsupported method: {method}")
23
+ return None
24
+
25
+ print(f"\n{method} {endpoint}")
26
+ print(f"Status: {response.status_code}")
27
+
28
+ if response.status_code == 200:
29
+ try:
30
+ result = response.json()
31
+ print("βœ… Success")
32
+ return result
33
+ except:
34
+ print(f"Response: {response.text[:200]}...")
35
+ return response.text
36
+ else:
37
+ print(f"❌ Error: {response.text}")
38
+ return None
39
+
40
+ except Exception as e:
41
+ print(f"❌ Connection Error: {e}")
42
+ return None
43
+
44
+ def main():
45
+ print("πŸ§ͺ FastAPI Client Test")
46
+ print("=" * 40)
47
+
48
+ # Test 1: Get status
49
+ print("\n1️⃣ Testing /status endpoint...")
50
+ status = test_endpoint("GET", "/status")
51
+ if status:
52
+ print(f" Bot running: {status.get('is_running', 'Unknown')}")
53
+ print(f" Active sessions: {len(status.get('active_sessions', []))}")
54
+
55
+ # Test 2: Get root
56
+ print("\n2️⃣ Testing / root endpoint...")
57
+ root = test_endpoint("GET", "/")
58
+
59
+ # Test 3: Try to start BTC trading (will fail if server not running)
60
+ print("\n3️⃣ Testing /start/BTCUSDT endpoint...")
61
+ start_result = test_endpoint("POST", "/start/BTCUSDT", params={"duration_hours": 1})
62
+ if start_result:
63
+ print(" BTC trading session started!")
64
+ else:
65
+ print(" (Expected to fail if API server not running)")
66
+
67
+ # Test 4: Get sessions
68
+ print("\n4️⃣ Testing /sessions endpoint...")
69
+ sessions = test_endpoint("GET", "/sessions")
70
+
71
+ print("\n" + "=" * 40)
72
+ print("πŸ“Š Test Complete")
73
+ print("\nTo run the API server:")
74
+ print(" python3 api_server.py")
75
+ print("\nTo start trading:")
76
+ print(" curl -X POST http://localhost:8000/start/BTCUSDT")
77
+ print("\nTo check status:")
78
+ print(" curl http://localhost:8000/status")
79
+
80
+ if __name__ == "__main__":
81
+ main()
test/test_api_raw.py ADDED
@@ -0,0 +1,176 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import requests
2
+ import time
3
+ import hashlib
4
+ import hmac
5
+ import uuid
6
+ import os
7
+ from dotenv import load_dotenv
8
+
9
+ load_dotenv()
10
+
11
+ api_key = os.getenv("BYBIT_API_KEY")
12
+ secret_key = os.getenv("BYBIT_API_SECRET")
13
+ httpClient = requests.Session()
14
+ recv_window = str(5000)
15
+ url = "https://api.bybit.com"
16
+
17
+ def HTTP_Request(endPoint, method, payload, Info):
18
+ global time_stamp
19
+ time_stamp = str(int(time.time() * 10 ** 3))
20
+ signature = genSignature(payload)
21
+ headers = {
22
+ 'X-BAPI-API-KEY': api_key,
23
+ 'X-BAPI-SIGN': signature,
24
+ 'X-BAPI-SIGN-TYPE': '2',
25
+ 'X-BAPI-TIMESTAMP': time_stamp,
26
+ 'X-BAPI-RECV-WINDOW': recv_window,
27
+ 'Content-Type': 'application/json'
28
+ }
29
+ if(method == "POST"):
30
+ response = httpClient.request(method, url + endPoint, headers=headers, data=payload)
31
+ else:
32
+ response = httpClient.request(method, url + endPoint + "?" + payload, headers=headers)
33
+ print(f"\n{Info}:")
34
+ print(f"Status Code: {response.status_code}")
35
+ print(f"Response: {response.text}")
36
+ print(f"Elapsed Time: {response.elapsed}")
37
+ return response
38
+
39
+ def genSignature(payload):
40
+ param_str = str(time_stamp) + api_key + recv_window + payload
41
+ hash = hmac.new(bytes(secret_key, "utf-8"), param_str.encode("utf-8"), hashlib.sha256)
42
+ signature = hash.hexdigest()
43
+ return signature
44
+
45
+ def test_wallet_balance():
46
+ print("Testing Wallet Balance...")
47
+ endpoint = "/v5/account/wallet-balance"
48
+ method = "GET"
49
+ params = 'accountType=UNIFIED'
50
+ response = HTTP_Request(endpoint, method, params, "Wallet Balance")
51
+
52
+ # Parse response to check for specific errors
53
+ try:
54
+ import json
55
+ resp_data = json.loads(response.text) if response.text else {}
56
+ ret_code = resp_data.get('retCode', -1)
57
+ ret_msg = resp_data.get('retMsg', 'Unknown error')
58
+
59
+ if ret_code == 0:
60
+ return True
61
+ else:
62
+ print(f" API Error: {ret_code} - {ret_msg}")
63
+ return False
64
+ except:
65
+ return response.status_code == 200
66
+
67
+ def test_positions():
68
+ print("Testing Positions...")
69
+ endpoint = "/v5/position/list"
70
+ method = "GET"
71
+ params = 'category=linear&settleCoin=USDT'
72
+ response = HTTP_Request(endpoint, method, params, "Positions")
73
+ return parse_api_response(response)
74
+
75
+ def test_create_order():
76
+ print("Testing Order Creation...")
77
+ print("Note: Order creation may fail due to symbol whitelisting or insufficient balance")
78
+ print("This is normal for testing - the bot will handle this gracefully")
79
+
80
+ endpoint = "/v5/order/create"
81
+ method = "POST"
82
+ orderLinkId = uuid.uuid4().hex
83
+
84
+ # Try market order with minimum viable amount
85
+ params = f'{{"category":"linear","symbol":"BTCUSDT","side":"Buy","orderType":"Limit","qty":"0.001","price":"84100","timeInForce":"GTC","orderLinkId":"{orderLinkId}"}}'
86
+ response = HTTP_Request(endpoint, method, params, "Create Order (Market)")
87
+ success = parse_api_response(response)
88
+
89
+ if not success:
90
+ print(" Market order failed - this is expected if symbol not whitelisted or insufficient balance")
91
+ print(" The bot can still function for monitoring and analysis")
92
+
93
+ return success, orderLinkId
94
+
95
+ def test_get_orders():
96
+ print("Testing Get Orders...")
97
+ endpoint = "/v5/order/realtime"
98
+ method = "GET"
99
+ params = 'category=linear&settleCoin=USDT'
100
+ response = HTTP_Request(endpoint, method, params, "Get Orders")
101
+ return parse_api_response(response)
102
+
103
+ def parse_api_response(response):
104
+ """Parse API response and return success status"""
105
+ try:
106
+ import json
107
+ resp_data = json.loads(response.text) if response.text else {}
108
+ ret_code = resp_data.get('retCode', -1)
109
+ ret_msg = resp_data.get('retMsg', 'Unknown error')
110
+
111
+ if ret_code == 0:
112
+ return True
113
+ else:
114
+ print(f" API Error: {ret_code} - {ret_msg}")
115
+ return False
116
+ except Exception as e:
117
+ print(f" Parse Error: {e}")
118
+ return response.status_code == 200
119
+
120
+ def main():
121
+ print("πŸ” Bybit API Raw HTTP Test")
122
+ print("=" * 50)
123
+
124
+ if not api_key or not secret_key:
125
+ print("❌ API credentials not found!")
126
+ return
127
+
128
+ print(f"API Key: {api_key[:10]}...")
129
+ print(f"Secret Key: {secret_key[:10]}...")
130
+ print(f"Testnet URL: {url}")
131
+
132
+ tests = [
133
+ ("Wallet Balance", test_wallet_balance),
134
+ ("Positions", test_positions),
135
+ ("Get Orders", test_get_orders),
136
+ ]
137
+
138
+ results = []
139
+ for test_name, test_func in tests:
140
+ try:
141
+ success = test_func()
142
+ results.append((test_name, success))
143
+ print(f"βœ… {test_name}: {'PASS' if success else 'FAIL'}")
144
+ except Exception as e:
145
+ print(f"❌ {test_name}: ERROR - {e}")
146
+ results.append((test_name, False))
147
+
148
+ # Test order creation (optional)
149
+ try:
150
+ print("\nTesting Order Creation (will fail safely if no balance)...")
151
+ order_success, order_id = test_create_order()
152
+ results.append(("Create Order", order_success))
153
+ except Exception as e:
154
+ print(f"❌ Create Order: ERROR - {e}")
155
+ results.append(("Create Order", False))
156
+
157
+ print("\n" + "=" * 50)
158
+ print("πŸ“Š Test Results:")
159
+ passed = sum(1 for _, success in results if success)
160
+ total = len(results)
161
+
162
+ for test_name, success in results:
163
+ status = "βœ… PASS" if success else "❌ FAIL"
164
+ print(f" {test_name}: {status}")
165
+
166
+ print(f"\n🎯 Overall: {passed}/{total} tests passed")
167
+
168
+ if passed == total:
169
+ print("πŸŽ‰ All API tests passed! Ready for trading.")
170
+ elif passed > 0:
171
+ print("⚠️ Some tests passed. Check permissions and account setup.")
172
+ else:
173
+ print("❌ All tests failed. Check API credentials and permissions.")
174
+
175
+ if __name__ == "__main__":
176
+ main()