Skip to content

Commit 188b22d

Browse files
committed
post overhaul cleanup
1 parent be06e4b commit 188b22d

File tree

3 files changed

+53
-43
lines changed

3 files changed

+53
-43
lines changed

api_client.py

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,10 @@
1111

1212

1313
class APIClient:
14-
def __init__(self):
14+
def __init__(self, initials):
15+
self.initials = initials
1516
self.account_numbers = None
16-
self.config = APIConfig
17+
self.config = APIConfig(self.initials)
1718
self.session = requests.Session()
1819
self.setup_logging()
1920
self.token_info = self.load_token()
@@ -23,7 +24,7 @@ def __init__(self):
2324
self.manual_authorization_flow()
2425

2526
def setup_logging(self):
26-
logging.basicConfig(**APIConfig.LOGGING_CONFIG)
27+
logging.basicConfig(**self.config.LOGGING_CONFIG)
2728
self.logger = logging.getLogger(__name__)
2829

2930
def ensure_valid_token(self):
@@ -42,7 +43,7 @@ def ensure_valid_token(self):
4243
def manual_authorization_flow(self):
4344
""" Handle the manual steps required to get the authorization code from the user. """
4445
self.logger.info("Starting manual authorization flow.")
45-
auth_url = f"{APIConfig.API_BASE_URL}/v1/oauth/authorize?client_id={APIConfig.APP_KEY}&redirect_uri={APIConfig.CALLBACK_URL}&response_type=code"
46+
auth_url = f"{self.config.API_BASE_URL}/v1/oauth/authorize?client_id={self.config.APP_KEY}&redirect_uri={self.config.CALLBACK_URL}&response_type=code"
4647
webbrowser.open(auth_url)
4748
self.logger.info(f"Please authorize the application by visiting: {auth_url}")
4849
response_url = ColorPrint.input(
@@ -91,26 +92,26 @@ def refresh_access_token(self):
9192
def save_token(self, token_data):
9293
""" Save token data securely. """
9394
token_data['expires_at'] = (datetime.now() + timedelta(seconds=token_data['expires_in'])).isoformat()
94-
with open('token_data.json', 'w') as f:
95+
with open(f'schwab_token_data_{self.initials}.json', 'w') as f:
9596
json.dump(token_data, f)
9697
self.logger.info("Token data saved successfully.")
9798

9899
def load_token(self):
99100
""" Load token data. """
100101
try:
101-
with open('token_data.json', 'r') as f:
102+
with open(f'schwab_token_data_{self.initials}.json', 'r') as f:
102103
token_data = json.load(f)
103104
return token_data
104105
except Exception as e:
105106
self.logger.warning(f"Loading token failed: {e}")
106107
return None
107108

108109
def validate_token(self, force=False):
109-
""" Validate the current token's validity. """
110-
print(self.token_info['expires_at'])
111-
print(datetime.now())
112-
print(datetime.fromisoformat(self.token_info['expires_at']))
113-
print(datetime.now() < datetime.fromisoformat(self.token_info['expires_at']))
110+
""" Validate the current token. """
111+
# print(self.token_info['expires_at'])
112+
# print(datetime.now())
113+
# print(datetime.fromisoformat(self.token_info['expires_at']))
114+
# print(datetime.now() < datetime.fromisoformat(self.token_info['expires_at']))
114115
if self.token_info and datetime.now() < datetime.fromisoformat(self.token_info['expires_at']):
115116
print(f"Token expires in {datetime.fromisoformat(self.token_info['expires_at']) - datetime.now()} seconds")
116117
return True

config.py

Lines changed: 30 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -6,31 +6,33 @@
66

77

88
class APIConfig:
9-
if SANDBOX:
10-
API_BASE_URL = "http://localhost:4020"
11-
TRADER_BASE_URL = API_BASE_URL
12-
ACCOUNTS_BASE_URL = f"{API_BASE_URL}/accounts"
13-
MARKET_DATA_BASE_URL = f"{API_BASE_URL}/marketdata"
14-
ORDERS_BASE_URL = ACCOUNTS_BASE_URL
15-
STREAMER_INFO_URL = f"{API_BASE_URL}/streamer-info"
16-
else:
17-
API_BASE_URL = "https://api.schwabapi.com"
18-
TRADER_BASE_URL = f"{API_BASE_URL}/trader/v1"
19-
ACCOUNTS_BASE_URL = f"{TRADER_BASE_URL}/accounts"
20-
MARKET_DATA_BASE_URL = f"{API_BASE_URL}/marketdata/v1"
21-
ORDERS_BASE_URL = ACCOUNTS_BASE_URL
22-
STREAMER_INFO_URL = f"{API_BASE_URL}/streamer-info"
23-
REQUEST_TIMEOUT = 30 # Timeout for API requests in seconds
24-
RETRY_STRATEGY = {
25-
'total': 3, # Total number of retries to allow
26-
'backoff_factor': 1 # Factor by which the delay between retries will increase
27-
}
28-
TOKEN_REFRESH_THRESHOLD_SECONDS = 300 # Time in seconds before token expiration to attempt refresh
29-
DEBUG_MODE = False
30-
LOGGING_CONFIG = {
31-
'level': 'INFO',
32-
'format': '%(asctime)s - %(name)s - %(levelname)s - %(message)s'
33-
}
34-
APP_KEY = os.getenv('APP_KEY')
35-
APP_SECRET = os.getenv('APP_SECRET')
36-
CALLBACK_URL = os.getenv('CALLBACK_URL')
9+
def __init__(self, initials):
10+
self.initials = initials
11+
if SANDBOX:
12+
self.API_BASE_URL = "http://localhost:4020"
13+
self.TRADER_BASE_URL = self.API_BASE_URL
14+
self.ACCOUNTS_BASE_URL = f"{self.API_BASE_URL}/accounts"
15+
self.MARKET_DATA_BASE_URL = f"{self.API_BASE_URL}/marketdata"
16+
self.ORDERS_BASE_URL = self.ACCOUNTS_BASE_URL
17+
self.STREAMER_INFO_URL = f"{self.API_BASE_URL}/streamer-info"
18+
else:
19+
self.API_BASE_URL = "https://api.schwabapi.com"
20+
self.TRADER_BASE_URL = f"{self.API_BASE_URL}/trader/v1"
21+
self.ACCOUNTS_BASE_URL = f"{self.TRADER_BASE_URL}/accounts"
22+
self.MARKET_DATA_BASE_URL = f"{self.API_BASE_URL}/marketdata/v1"
23+
self.ORDERS_BASE_URL = self.ACCOUNTS_BASE_URL
24+
self.STREAMER_INFO_URL = f"{self.API_BASE_URL}/streamer-info"
25+
self.REQUEST_TIMEOUT = 30 # Timeout for API requests in seconds
26+
self. RETRY_STRATEGY = {
27+
'total': 3, # Total number of retries to allow
28+
'backoff_factor': 1 # Factor by which the delay between retries will increase
29+
}
30+
self.TOKEN_REFRESH_THRESHOLD_SECONDS = 300 # Time in seconds before token expiration to attempt refresh
31+
self.DEBUG_MODE = False
32+
self.LOGGING_CONFIG = {
33+
'level': 'INFO',
34+
'format': '%(asctime)s - %(name)s - %(levelname)s - %(message)s'
35+
}
36+
self.APP_KEY = os.getenv(f'SCHWAB_APP_KEY_{self.initials}')
37+
self.APP_SECRET = os.getenv(f'SCHWAB_APP_SECRET_{self.initials}')
38+
self.CALLBACK_URL = os.getenv('CALLBACK_URL')

orders.py

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,21 @@
1+
from datetime import datetime, timezone, timedelta
2+
3+
14
class Orders:
25
def __init__(self, client):
36
self.client = client
47
self.base_url = client.config.ORDERS_BASE_URL
58

69
def get_orders(self, account_hash, max_results=100, from_entered_time=None, to_entered_time=None, status=None):
710
"""Retrieve a list of orders for a specified account."""
11+
if from_entered_time is None:
12+
from_entered_time = (datetime.now(timezone.utc) - timedelta(days=364)).isoformat(timespec='seconds')
13+
if to_entered_time is None:
14+
to_entered_time = datetime.now(timezone.utc).isoformat(timespec='seconds')
815
params = {
916
'maxResults': max_results,
10-
'fromEnteredTime': from_entered_time.isoformat() if from_entered_time else None,
11-
'toEnteredTime': to_entered_time.isoformat() if to_entered_time else None,
17+
'fromEnteredTime': from_entered_time,
18+
'toEnteredTime': to_entered_time,
1219
'status': status
1320
}
1421
endpoint = f"{self.base_url}/{account_hash}/orders"
@@ -27,9 +34,9 @@ def get_order(self, account_hash, order_id):
2734
def cancel_order(self, account_hash, order_id):
2835
"""Cancel a specific order."""
2936
endpoint = f"{self.base_url}/{account_hash}/orders/{order_id}"
30-
return self.client.delete(endpoint)
37+
return self.client.make_request(endpoint, method='DELETE')
3138

3239
def replace_order(self, account_hash, order_id, new_order_details):
3340
"""Replace an existing order with new details."""
3441
endpoint = f"{self.base_url}/{account_hash}/orders/{order_id}"
35-
return self.client.put(endpoint, data=new_order_details)
42+
return self.client.make_request(endpoint, method='PUT', data=new_order_details)

0 commit comments

Comments
 (0)