Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Mask Account Numbers when Printed #116

Merged
merged 14 commits into from
Jan 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 9 additions & 11 deletions fidelityAPI.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
check_if_page_loaded,
getDriver,
killSeleniumDriver,
maskString,
printAndDiscord,
printHoldings,
stockOrder,
Expand Down Expand Up @@ -169,13 +170,10 @@ def fidelity_account_info(driver: webdriver) -> dict or None:
)
)
account_numbers = javascript_get_classname(driver, "acct-selector__acct-num")
print(f"Accounts: {account_numbers}")
# Get account balances via javascript
account_values = javascript_get_classname(driver, "acct-selector__acct-balance")
print(f"Values: {account_values}")
# Get account names via javascript
account_types = javascript_get_classname(driver, "acct-selector__acct-name")
print(f"Account Names: {account_types}")
# Make sure all lists are the same length
if not (
len(account_numbers) == len(account_values)
Expand Down Expand Up @@ -242,11 +240,10 @@ def fidelity_holdings(fidelity_o: Brokerage, loop=None):
r"(?<=\s{2})[a-zA-Z]{3,4}(?=\s{2})", stocks_list[i]
)
stocks_list = stocks_list[0]
print(f"Stocks: {stocks_list}")
holdings_info = javascript_get_classname(
driver, "ag-center-cols-container"
)
print(f"Holdings Info: {holdings_info}")
# holdings_info = javascript_get_classname(
# driver, "ag-center-cols-container"
# )
# print(f"Holdings Info: {holdings_info}")
for stock in stocks_list:
fidelity_o.set_holdings(key, account, stock, "N/A", "N/A")
except Exception as e:
Expand Down Expand Up @@ -318,7 +315,8 @@ def fidelity_transaction(fidelity_o: Brokerage, orderObj: stockOrder, loop=None)
accounts_dropdown_in = test.find_elements(
by=By.CSS_SELECTOR, value="li"
)
account_label = accounts_dropdown_in[x].text
account_number = fidelity_o.get_account_numbers(key)[x]
account_label = maskString(account_number)
accounts_dropdown_in[x].click()
sleep(1)
# Type in ticker
Expand Down Expand Up @@ -520,13 +518,13 @@ def fidelity_transaction(fidelity_o: Brokerage, orderObj: stockOrder, loop=None)
"arguments[0].click();", error_dismiss
)
printAndDiscord(
f"{key} {account_label}: {orderObj.get_action()} {orderObj.get_amount()} shares of {s}. DID NOT COMPLETE! \nEither this account does not have enough shares, or an order is already pending.",
f"{key} account {account_label}: {orderObj.get_action()} {orderObj.get_amount()} shares of {s}. DID NOT COMPLETE! \nEither this account does not have enough shares, or an order is already pending.",
loop,
)
# Send confirmation
else:
printAndDiscord(
f"DRY: {key} {account_label}: {orderObj.get_action()} {orderObj.get_amount()} shares of {s}",
f"DRY: {key} account {account_label}: {orderObj.get_action()} {orderObj.get_amount()} shares of {s}",
loop,
)
sleep(3)
Expand Down
11 changes: 10 additions & 1 deletion helperAPI.py
Original file line number Diff line number Diff line change
Expand Up @@ -450,6 +450,15 @@ async def processQueue():
task_queue.task_done()


def maskString(string):
# Mask string (12345678 -> xxxx5678)
string = str(string)
if len(string) < 4:
return string
masked = "x" * (len(string) - 4) + string[-4:]
return masked


def printHoldings(brokerObj: Brokerage, loop=None):
# Helper function for holdings formatting
printAndDiscord(
Expand All @@ -458,7 +467,7 @@ def printHoldings(brokerObj: Brokerage, loop=None):
)
for key in brokerObj.get_account_numbers():
for account in brokerObj.get_account_numbers(key):
printAndDiscord(f"{key} ({account}):", loop)
printAndDiscord(f"{key} ({maskString(account)}):", loop)
holdings = brokerObj.get_holdings(key, account)
if holdings == {}:
printAndDiscord("No holdings in Account\n", loop)
Expand Down
20 changes: 11 additions & 9 deletions robinhoodAPI.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
import robin_stocks.robinhood as rh
from dotenv import load_dotenv

from helperAPI import Brokerage, printAndDiscord, printHoldings, stockOrder
from helperAPI import Brokerage, maskString, printAndDiscord, printHoldings, stockOrder


def robinhood_init(ROBINHOOD_EXTERNAL=None):
Expand Down Expand Up @@ -52,7 +52,7 @@ def robinhood_init(ROBINHOOD_EXTERNAL=None):
)
atype = rh.account.load_account_profile(info="type", account_number=an)
rh_obj.set_account_type(name, an, atype)
print(f"Found {atype} account {an}")
print(f"Found {atype} account {maskString(an)}")
# Check for IRA accounts
if (len(account) > 3) and (account[3] != "NA"):
iras = [account[3]]
Expand All @@ -61,6 +61,7 @@ def robinhood_init(ROBINHOOD_EXTERNAL=None):
for ira in iras:
# Make sure it's different from the normal account number
if ira == an:
ira = maskString(ira)
print(
f"ERROR: IRA account {ira} is the same as margin account. Please remove {an} from your .env file."
)
Expand All @@ -69,9 +70,9 @@ def robinhood_init(ROBINHOOD_EXTERNAL=None):
info="account_number", account_number=ira
)
if ira_num is None:
print(f"Unable to lookup IRA account {ira}")
print(f"Unable to lookup IRA account {maskString(ira)}")
continue
print(f"Found IRA account {ira_num}")
print(f"Found IRA account {maskString(ira_num)}")
rh_obj.set_account_number(name, ira_num)
rh_obj.set_account_totals(
name,
Expand Down Expand Up @@ -136,6 +137,7 @@ def robinhood_transaction(rho: Brokerage, orderObj: stockOrder, loop=None):
)
for account in rho.get_account_numbers(key):
obj: rh = rho.get_logged_in_objects(key)
print_account = maskString(account)
if not orderObj.get_dry():
try:
# Market order
Expand All @@ -149,7 +151,7 @@ def robinhood_transaction(rho: Brokerage, orderObj: stockOrder, loop=None):
# Limit order fallback
if market_order is None:
printAndDiscord(
f"{key}: Error {orderObj.get_action()}ing {orderObj.get_amount()} of {s} in {account}, trying Limit Order",
f"{key}: Error {orderObj.get_action()}ing {orderObj.get_amount()} of {s} in {print_account}, trying Limit Order",
loop,
)
ask = obj.get_latest_price(s, priceType="ask_price")[0]
Expand Down Expand Up @@ -186,30 +188,30 @@ def robinhood_transaction(rho: Brokerage, orderObj: stockOrder, loop=None):
)
if limit_order is None:
printAndDiscord(
f"{key}: Error {orderObj.get_action()}ing {orderObj.get_amount()} of {s} in {account}",
f"{key}: Error {orderObj.get_action()}ing {orderObj.get_amount()} of {s} in {print_account}",
loop,
)
continue
message = "Success"
if limit_order.get("non_field_errors") is not None:
message = limit_order["non_field_errors"]
printAndDiscord(
f"{key}: {orderObj.get_action()} {orderObj.get_amount()} of {s} in {account} @ {price}: {message}",
f"{key}: {orderObj.get_action()} {orderObj.get_amount()} of {s} in {print_account} @ {price}: {message}",
loop,
)
else:
message = "Success"
if market_order.get("non_field_errors") is not None:
message = market_order["non_field_errors"]
printAndDiscord(
f"{key}: {orderObj.get_action()} {orderObj.get_amount()} of {s} in {account}: {message}",
f"{key}: {orderObj.get_action()} {orderObj.get_amount()} of {s} in {print_account}: {message}",
loop,
)
except Exception as e:
traceback.format_exc()
printAndDiscord(f"{key} Error submitting order: {e}", loop)
else:
printAndDiscord(
f"{key} {account} Running in DRY mode. Transaction would've been: {orderObj.get_action()} {orderObj.get_amount()} of {s}",
f"{key} {print_account} Running in DRY mode. Transaction would've been: {orderObj.get_action()} {orderObj.get_amount()} of {s}",
loop,
)
16 changes: 10 additions & 6 deletions schwabAPI.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
from dotenv import load_dotenv
from schwab_api import Schwab

from helperAPI import Brokerage, printAndDiscord, printHoldings, stockOrder
from helperAPI import Brokerage, maskString, printAndDiscord, printHoldings, stockOrder


def schwab_init(SCHWAB_EXTERNAL=None):
Expand Down Expand Up @@ -39,7 +39,8 @@ def schwab_init(SCHWAB_EXTERNAL=None):
)
account_info = schwab.get_account_info_v2()
account_list = list(account_info.keys())
print(f"The following Schwab accounts were found: {account_list}")
print_accounts = [maskString(a) for a in account_list]
print(f"The following Schwab accounts were found: {print_accounts}")
print("Logged in to Schwab!")
schwab_obj.set_logged_in_object(name, schwab)
for account in account_list:
Expand All @@ -48,8 +49,8 @@ def schwab_init(SCHWAB_EXTERNAL=None):
name, account, account_info[account]["account_value"]
)
except Exception as e:
print(traceback.format_exc())
print(f"Error logging in to Schwab: {e}")
print(traceback.format_exc())
return None
return schwab_obj

Expand All @@ -76,6 +77,7 @@ def schwab_holdings(schwab_o: Brokerage, loop=None):
schwab_o.set_holdings(key, account, sym, qty, current_price)
except Exception as e:
printAndDiscord(f"{key} {account}: Error getting holdings: {e}", loop)
print(traceback.format_exc())
printHoldings(schwab_o, loop)


Expand All @@ -94,6 +96,7 @@ def schwab_transaction(schwab_o: Brokerage, orderObj: stockOrder, loop=None):
)
obj: Schwab = schwab_o.get_logged_in_objects(key)
for account in schwab_o.get_account_numbers(key):
print_account = maskString(account)
# If DRY is True, don't actually make the transaction
if orderObj.get_dry():
printAndDiscord(
Expand All @@ -108,19 +111,20 @@ def schwab_transaction(schwab_o: Brokerage, orderObj: stockOrder, loop=None):
dry_run=orderObj.get_dry(),
)
printAndDiscord(
f"{key} account {account}: The order verification was "
f"{key} account {print_account}: The order verification was "
+ "successful"
if success
else "unsuccessful",
loop,
)
if not success:
printAndDiscord(
f"{key} account {account}: The order verification produced the following messages: {messages}",
f"{key} account {print_account}: The order verification produced the following messages: {messages}",
loop,
)
except Exception as e:
printAndDiscord(
f"{key} {account}: Error submitting order: {e}", loop
f"{key} {print_account}: Error submitting order: {e}", loop
)
print(traceback.format_exc())
sleep(1)
15 changes: 7 additions & 8 deletions tastyAPI.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
from tastytrade.streamer import DataStreamer
from tastytrade.utils import TastytradeError

from helperAPI import Brokerage, printAndDiscord, printHoldings, stockOrder
from helperAPI import Brokerage, maskString, printAndDiscord, printHoldings, stockOrder


def order_setup(tt: ProductionSession, order_type, stock_price, stock, amount):
Expand Down Expand Up @@ -121,6 +121,7 @@ async def tastytrade_execute(tt_o: Brokerage, orderObj: stockOrder, loop=None):
loop=loop,
)
for i, acct in enumerate(tt_o.get_account_numbers(key)):
print_account = maskString(acct)
try:
acct: Account = accounts[i]
# Set order type
Expand All @@ -141,7 +142,7 @@ async def tastytrade_execute(tt_o: Brokerage, orderObj: stockOrder, loop=None):
order_status = placed_order.order.status.value
# Check order status
if order_status in ["Received", "Routed"]:
message = f"{key} {acct.account_number}: {orderObj.get_action()} {orderObj.get_amount()} of {s} Order: {placed_order.order.id} Status: {order_status}"
message = f"{key} {print_account}: {orderObj.get_action()} {orderObj.get_amount()} of {s} Order: {placed_order.order.id} Status: {order_status}"
if orderObj.get_dry():
message = f"{key} Running in DRY mode. Transaction would've been: {orderObj.get_action()} {orderObj.get_amount()} of {s}"
printAndDiscord(message, loop=loop)
Expand All @@ -151,7 +152,7 @@ async def tastytrade_execute(tt_o: Brokerage, orderObj: stockOrder, loop=None):
stock_limit = await streamer.oneshot(EventType.PROFILE, [s])
stock_quote = await streamer.oneshot(EventType.QUOTE, [s])
printAndDiscord(
f"{key} {acct.account_number} Error: {order_status} Trying Limit order...",
f"{key} {print_account} Error: {order_status} Trying Limit order...",
loop=loop,
)
# Get limit price
Expand Down Expand Up @@ -181,20 +182,18 @@ async def tastytrade_execute(tt_o: Brokerage, orderObj: stockOrder, loop=None):
)
# Check order status
if order_status in ["Received", "Routed"]:
message = f"{key} {acct.account_number}: {orderObj.get_action()} {orderObj.get_amount()} of {s} Order: {placed_order.order.id} Status: {order_status}"
message = f"{key} {print_account}: {orderObj.get_action()} {orderObj.get_amount()} of {s} Order: {placed_order.order.id} Status: {order_status}"
if orderObj.get_dry():
message = f"{key} Running in DRY mode. Transaction would've been: {orderObj.get_action()} {orderObj.get_amount()} of {s}"
printAndDiscord(message, loop=loop)
elif order_status == "Rejected":
# Only want this message if it fails both orders.
printAndDiscord(
f"{key} Error placing order: {placed_order.order.id} on account {acct.account_number}: {order_status}",
f"{key} Error placing order: {placed_order.order.id} on account {print_account}: {order_status}",
loop=loop,
)
except TastytradeError as te:
printAndDiscord(
f"{key} {acct.account_number}: Error: {te}", loop=loop
)
printAndDiscord(f"{key} {print_account}: Error: {te}", loop=loop)


def tastytrade_transaction(tt: Brokerage, orderObj: stockOrder, loop=None):
Expand Down
Loading