11from __future__ import annotations
2- from typing import List , Optional
2+ from typing import List , Optional , Union , Dict
33
44import os
55from pathlib import Path
66import json
77from enum import Enum
8- from typing import Union
98
109from pydantic import BaseModel , HttpUrl , ValidationError , validator , DirectoryPath
1110
1716class Exchanges (Enum ):
1817 BYBIT = "bybit"
1918
20-
2119class Messengers (Enum ):
2220 DISCORD = "discord"
2321 TELEGRAM = "telegram"
2422
25-
2623class API (BaseModel ):
2724 filename : str = "quantdatav2.json"
2825 mode : str = "remote"
@@ -36,7 +33,6 @@ class Hotkeys(BaseModel):
3633 enter_short : str = "3"
3734 take_profit_short : str = "4"
3835
39-
4036class Bot (BaseModel ):
4137 bot_name : str
4238 volume_check : bool = True
@@ -75,10 +71,8 @@ class Bot(BaseModel):
7571 whitelist : List [str ] = []
7672 dashboard_enabled : bool = False
7773 shared_data_path : Optional [str ] = None
78- #risk_management: Optional[dict] = None
7974 linear_grid : Optional [dict ] = None
8075 hotkeys : Hotkeys
81- # shared_data_path: Optional[DirectoryPath] = None
8276
8377 @validator ('hotkeys' )
8478 def validate_hotkeys (cls , value ):
@@ -211,13 +205,13 @@ def check_volume_check_is_bool(cls, v):
211205 if not isinstance (v , bool ):
212206 raise ValueError ("volume_check must be a boolean" )
213207 return v
214-
208+
215209class Exchange (BaseModel ):
216210 name : str
217211 account_name : str
218212 api_key : str
219213 api_secret : str
220- passphrase : str = None
214+ passphrase : Optional [ str ] = None
221215 symbols_allowed : int = 12
222216
223217class Logger (BaseModel ):
@@ -251,13 +245,12 @@ class Telegram(BaseModel):
251245 bot_token : str
252246 chat_id : str
253247
254-
255248class Config (BaseModel ):
256249 api : API
257250 bot : Bot
258- exchanges : List [Exchange ] # <-- Changed from List[Exchange]
251+ exchanges : List [Exchange ]
259252 logger : Logger
260- messengers : dict [str , Union [Discord , Telegram ]]
253+ messengers : Dict [str , Union [Discord , Telegram ]]
261254
262255def resolve_shared_data_path (relative_path : str ) -> Path :
263256 # Get the directory of the config file
@@ -271,47 +264,26 @@ def resolve_shared_data_path(relative_path: str) -> Path:
271264
272265 return absolute_path
273266
274- def load_config (path ):
275- if not path .is_file ():
276- raise ValueError (f"{ path } does not exist" )
277- else :
278- with open (path ) as f :
279- try :
280- data = json .load (f )
281- except json .JSONDecodeError as exc :
282- raise ValueError (
283- f"ERROR: Invalid JSON: { exc .msg } , line { exc .lineno } , column { exc .colno } "
284- )
285- try :
286- config_data = Config (** data )
287-
288- # Resolve shared_data_path if it's provided
289- if config_data .bot .shared_data_path :
290- config_data .bot .shared_data_path = str (resolve_shared_data_path (config_data .bot .shared_data_path ))
291-
292- return config_data
293- except ValidationError as e :
294- # Enhanced error output
295- error_details = "\n " .join ([f"{ err ['loc' ]} - { err ['msg' ]} " for err in e .errors ()])
296- raise ValueError (f"Configuration Error(s):\n { error_details } " )
297-
298- # def load_config(path):
299- # if not path.is_file():
300- # raise ValueError(f"{path} does not exist")
301- # else:
302- # f = open(path)
303- # try:
304- # data = json.load(f)
305- # except json.JSONDecodeError as exc:
306- # raise ValueError(
307- # f"ERROR: Invalid JSON: {exc.msg}, line {exc.lineno}, column {exc.colno}"
308- # )
309- # try:
310- # return Config(**data)
311- # except ValidationError as e:
312- # # Enhancing the error output for better clarity
313- # error_details = "\n".join([f"{err['loc']} - {err['msg']}" for err in e.errors()])
314- # raise ValueError(f"Configuration Error(s):\n{error_details}")
267+ def load_json (file_path : Path ) -> dict :
268+ with open (file_path , 'r' ) as file :
269+ return json .load (file )
270+
271+ def load_config (config_path : Path , account_path : Path ) -> Config :
272+ config_data = load_json (config_path )
273+ account_data = load_json (account_path )
274+
275+ # Merge account data into config data
276+ for exchange in config_data ['exchanges' ]:
277+ for account in account_data ['exchanges' ]:
278+ if exchange ['name' ] == account ['name' ] and exchange ['account_name' ] == account ['account_name' ]:
279+ exchange .update ({
280+ 'api_key' : account ['api_key' ],
281+ 'api_secret' : account ['api_secret' ],
282+ 'passphrase' : account .get ('passphrase' , None )
283+ })
284+ break
285+
286+ return Config (** config_data )
315287
316288def get_exchange_name (cli_exchange_name ):
317289 if cli_exchange_name :
@@ -344,70 +316,3 @@ def get_exchange_credentials(exchange_name, account_name):
344316 return api_key , secret_key , passphrase , symbols_allowed
345317 else :
346318 raise ValueError (f"Account { account_name } for exchange { exchange_name } not found in the config file." )
347-
348- # def get_exchange_credentials(exchange_name, account_name):
349- # with open('config.json') as file:
350- # data = json.load(file)
351- # exchange_data = None
352- # for exchange in data['exchanges']:
353- # if exchange['name'] == exchange_name and exchange['account_name'] == account_name:
354- # exchange_data = exchange
355- # break
356- # if exchange_data:
357- # api_key = exchange_data['api_key']
358- # secret_key = exchange_data['api_secret']
359- # passphrase = exchange_data.get('passphrase')
360- # symbols_allowed = exchange_data.get('symbols_allowed', 12) # Default to 12 if not specified
361- # return api_key, secret_key, passphrase, symbols_allowed
362- # else:
363- # raise ValueError(f"Account {account_name} for exchange {exchange_name} not found in the config file.")
364-
365- # def get_exchange_credentials(exchange_name, account_name):
366- # with open('config.json') as file:
367- # data = json.load(file)
368- # exchange_data = None
369- # for exchange in data['exchanges']:
370- # if exchange['name'] == exchange_name and exchange['account_name'] == account_name:
371- # exchange_data = exchange
372- # break
373- # if exchange_data:
374- # api_key = exchange_data['api_key']
375- # secret_key = exchange_data['api_secret']
376- # passphrase = exchange_data.get('passphrase') # Not all exchanges require a passphrase
377- # return api_key, secret_key, passphrase
378- # else:
379- # raise ValueError(f"Account {account_name} for exchange {exchange_name} not found in the config file.")
380-
381- # def get_exchange_credentials(exchange_name):
382- # with open('config.json') as file:
383- # data = json.load(file)
384- # exchange_data = None
385- # for exchange in data['exchanges']:
386- # if exchange['name'] == exchange_name:
387- # exchange_data = exchange
388- # break
389- # if exchange_data:
390- # api_key = exchange_data['api_key']
391- # secret_key = exchange_data['api_secret']
392- # passphrase = exchange_data.get('passphrase') # Not all exchanges require a passphrase
393- # return api_key, secret_key, passphrase
394- # else:
395- # raise ValueError(f"Exchange {exchange_name} not found in the config file.")
396-
397-
398- # def get_exchange_name(cli_exchange_name):
399- # if cli_exchange_name:
400- # return cli_exchange_name
401- # else:
402- # with open('config.json') as file:
403- # data = json.load(file)
404- # return data['exchange']
405-
406- # def get_exchange_credentials(exchange_name):
407- # with open('config.json') as file:
408- # data = json.load(file)
409- # exchange_data = data['exchanges'][exchange_name]
410- # api_key = exchange_data['api_key']
411- # secret_key = exchange_data['secret_key']
412- # passphrase = exchange_data.get('passphrase') # Not all exchanges require a passphrase
413- # return api_key, secret_key, passphrase
0 commit comments