File size: 3,370 Bytes
66b7a93
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
import mongoose from 'mongoose';

const stateSchema = new mongoose.Schema({
  stateId: { type: String, default: 'global_state', unique: true },
  activeTrades: { type: Array, default: [] },
  tradeHistory: { type: Array, default: [] },
  accountBalance: { type: Number, default: 5000.0 },
  dailyLosses: { type: Number, default: 0 },
  lastExecutedCandleTime: { type: Map, of: Number, default: {} },
  lastClosedTime: { type: Map, of: Number, default: {} },
  lastResetDate: { type: String, default: '' }
}, { minimize: false });

const StateModel = mongoose.model('TerminalState', stateSchema);

export class DBManager {
  constructor() {
    this.isConnected = false;
    this.cachedState = null;
  }

  async connect(uri) {
    if (this.isConnected) return;
    try {
      console.log('[DBManager] Connecting to MongoDB Atlas...');
      await mongoose.connect(uri);
      this.isConnected = true;
      console.log('[DBManager] Connected securely to MongoDB Atlas.');
      // Initialize state if not exists
      await this.loadState();
    } catch (err) {
      console.error('[DBManager] Connection failed:', err);
      throw err;
    }
  }

  async loadState() {
    try {
      let state = await StateModel.findOne({ stateId: 'global_state' });
      if (!state) {
        console.log('[DBManager] Global state document not found. Creating new global state.');
        state = new StateModel({
          lastResetDate: new Date().toDateString()
        });
        await state.save();
      }
      this.cachedState = state;
      return {
        activeTrades: state.activeTrades || [],
        tradeHistory: state.tradeHistory || [],
        accountBalance: state.accountBalance ?? 5000.0,
        dailyLosses: state.dailyLosses ?? 0,
        lastExecutedCandleTime: Object.fromEntries(state.lastExecutedCandleTime || new Map()),
        lastClosedTime: Object.fromEntries(state.lastClosedTime || new Map()),
        lastResetDate: state.lastResetDate
      };
    } catch (err) {
      console.error('[DBManager] Error loading state:', err);
      return {
        activeTrades: [],
        tradeHistory: [],
        accountBalance: 5000.0,
        dailyLosses: 0,
        lastExecutedCandleTime: {},
        lastClosedTime: {},
        lastResetDate: new Date().toDateString()
      };
    }
  }

  async saveActiveTrades(activeTrades) {
    this._updateState({ activeTrades });
  }

  async saveTradeHistory(tradeHistory) {
    this._updateState({ tradeHistory });
  }

  async saveDailyLosses(dailyLosses, date) {
    const update = { dailyLosses };
    if (date) update.lastResetDate = date;
    this._updateState(update);
  }

  async saveAccountBalance(accountBalance) {
    this._updateState({ accountBalance });
  }

  async saveLastExecutedCandleTime(lastExecutedCandleTime) {
    this._updateState({ lastExecutedCandleTime });
  }

  async saveLastClosedTime(lastClosedTime) {
    this._updateState({ lastClosedTime });
  }

  /** @private */
  async _updateState(fields) {
    if (!this.isConnected) {
      console.warn('[DBManager] Not connected to database. Bypass saving.');
      return;
    }
    try {
      await StateModel.updateOne({ stateId: 'global_state' }, { $set: fields }, { upsert: true });
    } catch (err) {
      console.error('[DBManager] Error updating state fields:', fields, err);
    }
  }
}

export default DBManager;