From 7ce70202fa9f3c66d87732703bdc718cb2b149d1 Mon Sep 17 00:00:00 2001 From: maxxrk Date: Sat, 11 May 2024 16:13:51 -0500 Subject: [PATCH 01/24] add vanguard --- .env.example | 4 + .gitignore | 1 + README.md | 17 +++- autoRSA.py | 8 +- requirements.txt | 3 +- vanguardAPI.py | 234 +++++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 262 insertions(+), 5 deletions(-) create mode 100644 vanguardAPI.py diff --git a/.env.example b/.env.example index a8c9ef3d..b2993885 100644 --- a/.env.example +++ b/.env.example @@ -53,6 +53,10 @@ TRADIER= # TASTYTRADE=TASTYTRADE_USERNAME:TASTYTRADE_PASSWORD TASTYTRADE= +# Vanguard +# VANGUARD=VANGUARD_USERNAME:VANGUARD_PASSWORD:PHONE_LAST_FOUR:DEBUG(Optional) TRUE/FALSE +VANGUARD= + # Webull # WEBULL=WEBULL_USERNAME:WEBULL_PASSWORD:WEBULL_DID:WEBULL_TRADING_PIN WEBULL= \ No newline at end of file diff --git a/.gitignore b/.gitignore index ef18a474..7c76335b 100644 --- a/.gitignore +++ b/.gitignore @@ -9,3 +9,4 @@ src/ test* *venv/ .vscode/ +*.zip diff --git a/README.md b/README.md index f2329b78..9d0acb32 100644 --- a/README.md +++ b/README.md @@ -217,11 +217,24 @@ Your `WEBULL_USERNAME` can be your email or phone number. If using a phone numbe To get your Webull DID, follow this [guide](https://github.com/tedchou12/webull/wiki/Workaround-for-Login-%E2%80%90-Method-2). +### Vanguard +Made by [MaxxRK](https://github.com/MaxxRK/) using the [vanguard-api](https://github.com/MaxxRK/vanguard-api). Go give them a ⭐ + +Required `.env` variables: +- `VANGUARD_USERNAME` +- `VANGUARD_PASSWORD` +- `CELL_PHONE_LAST_FOUR` + +Optional `.env` variables: +- `DEBUG` (Set to `True` to enable debug mode) + +`.env` file format: +- `VANGUARD=VANGUARD_USERNAME:VANGUARD_PASSWORD:PHONE_LAST_FOUR:DEBUG` + + ### 🤷‍♂️ Maybe future brokerages 🤷‍♀️ #### Ally Ally disabled their official API, so all Ally packages don't work. I am attempting to reverse engineer their API, and will add it if I get it working. Otherwise, I will use Selenium or Playwright. -#### Vanguard -Will be added using Selenium or Playwright. #### SoFi Will be added using Selenium or Playwright. ### 👎 Never working brokerages 👎 diff --git a/autoRSA.py b/autoRSA.py index e6708a84..a7165caf 100644 --- a/autoRSA.py +++ b/autoRSA.py @@ -28,6 +28,7 @@ from schwabAPI import * from tastyAPI import * from tradierAPI import * + from vanguardAPI import * from webullAPI import * except Exception as e: print(f"Error importing libraries: {e}") @@ -49,6 +50,7 @@ "schwab", "tastytrade", "tradier", + "vanguard", "webull", ] DAY1_BROKERS = [ @@ -76,6 +78,8 @@ def nicknames(broker): return "robinhood" if broker == "tasty": return "tastytrade" + if broker == "vg": + return "vanguard" if broker == "wb": return "webull" return broker @@ -103,7 +107,7 @@ def fun_run(orderObj: stockOrder, command, botObj=None, loop=None): orderObj.set_logged_in( globals()[fun_name](botObj=botObj, loop=loop), broker ) - elif broker.lower() == "chase": + elif broker.lower() in ["chase", "vanguard"]: fun_name = broker + "_run" # PLAYWRIGHT_BROKERS have to run all transactions with one function th = ThreadHandler( @@ -126,7 +130,7 @@ def fun_run(orderObj: stockOrder, command, botObj=None, loop=None): orderObj.set_logged_in(globals()[fun_name](), broker) print() - if broker.lower() != "chase": + if broker.lower() not in ["chase", "vanguard"]: # Verify broker is logged in orderObj.order_validate(preLogin=False) logged_in_broker = orderObj.get_logged_in(broker) diff --git a/requirements.txt b/requirements.txt index bb0c32d3..0f864fab 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,5 +1,5 @@ asyncio==3.4.3 -chaseinvest-api==0.1.1 +chaseinvest-api==0.1.4 discord.py==2.3.2 firstrade==0.0.15 GitPython==3.1.43 @@ -11,4 +11,5 @@ requests==2.31.0 schwab-api==0.4.0 selenium==4.20.0 tastytrade==8.0 +vanguard-api==0.0.5 -e git+https://github.com/NelsonDane/webull.git@ef14ae63f9e1436fbea77fe864df54847cf2f730#egg=webull diff --git a/vanguardAPI.py b/vanguardAPI.py new file mode 100644 index 00000000..a4425d60 --- /dev/null +++ b/vanguardAPI.py @@ -0,0 +1,234 @@ +# Donald Ryan Gullett(MaxxRK) +# Vanguard API + +import asyncio +import os +import pprint +import traceback + +from vanguard import account as vg_account +from vanguard import order, session +from dotenv import load_dotenv + +from helperAPI import ( + Brokerage, + getOTPCodeDiscord, + maskString, + printAndDiscord, + printHoldings, + stockOrder, +) + + +def vanguard_run( + orderObj: stockOrder, command=None, botObj=None, loop=None +): + # Initialize .env file + load_dotenv() + # Import Vanguard account + if not os.getenv("VANGUARD"): + print("Vanguard not found, skipping...") + return None + accounts = ( + os.environ["VANGUARD"].strip().split(",") + ) + # Set the functions to be run + _, second_command = command + + for account in accounts: + index = accounts.index(account) + 1 + success = vanguard_init( + account=account, + index=index, + botObj=botObj, + loop=loop, + ) + if success is not None: + orderObj.set_logged_in(success, "vanguard") + if second_command == "_holdings": + vanguard_holdings(success, loop=loop) + else: + vanguard_transaction(success, orderObj, loop=loop) + return None + + +def vanguard_init(account, index, botObj=None, loop=None): + # Log in to Vanguard account + print("Logging in to Vanguard...") + vanguard_obj = Brokerage("VANGUARD") + name = f"Vanguard {index}" + try: + account = account.split(":") + debug = bool(account[3]) if len(account) == 4 else False + vg_session = session.VanguardSession( + title=f"Vanguard_{index}", + headless=False, + profile_path="./creds", + debug=debug + ) + need_second = vg_session.login(account[0], account[1], account[2]) + if need_second: + if botObj is None and loop is None: + vg_session.login_two(input("Enter code: ")) + else: + sms_code = asyncio.run_coroutine_threadsafe( + getOTPCodeDiscord(botObj, name, code_len=8, loop=loop), loop + ).result() + if sms_code is None: + raise Exception(f"Vanguard {index} code not received in time...", loop) + vg_session.login_two(sms_code) + all_accounts = vg_account.AllAccount(vg_session) + success = all_accounts.get_holdings() + if success is False: + raise Exception("Error getting account details") + print("Logged in to Vanguard!") + vanguard_obj.set_logged_in_object(name, vg_session) + print_accounts = [] + for acct in all_accounts.account_totals.keys(): + vanguard_obj.set_account_number(name, acct) + vanguard_obj.set_account_totals(name, acct, all_accounts.account_totals[acct]) + print_accounts.append(acct) + print(f"The following Vanguard accounts were found: {print_accounts}") + except Exception as e: + vg_session.close_browser() + print(f"Error logging in to Vanguard: {e}") + print(traceback.format_exc()) + return None + return vanguard_obj + + +def vanguard_holdings(vanguard_o: Brokerage, loop=None): + # Get holdings on each account + for key in vanguard_o.get_account_numbers(): + try: + obj: session.VanguardSession = vanguard_o.get_logged_in_objects(key) + all_accounts = vg_account.AllAccount(obj) + if all_accounts is None: + raise Exception("Error getting account details") + success = all_accounts.get_holdings() + if success: + for account in all_accounts.accounts_positions.keys(): + for type in all_accounts.accounts_positions[account].keys(): + for stock in all_accounts.accounts_positions[account][type]: + vanguard_o.set_holdings(key, account, stock["symbol"], stock["quantity"], stock["price"]) + else: + raise Exception("Vanguard-api failed to retrieve holdings.") + except Exception as e: + obj.close_browser() + printAndDiscord(f"{key} {account}: Error getting holdings: {e}", loop) + print(traceback.format_exc()) + continue + printHoldings(vanguard_o, loop) + obj.close_browser() + + +def vanguard_transaction(vanguard_o: Brokerage, orderObj: stockOrder, loop=None): + print() + print("==============================") + print("Vanguard") + print("==============================") + print() + # Buy on each account + for s in orderObj.get_stocks(): + for key in vanguard_o.get_account_numbers(): + printAndDiscord( + f"{key} {orderObj.get_action()}ing {orderObj.get_amount()} {s} @ {orderObj.get_price()}", + loop, + ) + try: + for account in vanguard_o.get_account_numbers(key): + print_account = maskString(account) + obj: session.VanguardSession = vanguard_o.get_logged_in_objects(key) + # If DRY is True, don't actually make the transaction + if orderObj.get_dry(): + printAndDiscord( + "Running in DRY mode. No transactions will be made.", loop + ) + vg_order = order.Order(obj) + price_type = order.PriceType.MARKET + if orderObj.get_action().capitalize() == "Buy": + order_type = order.OrderSide.BUY + else: + order_type = order.OrderSide.SELL + messages = vg_order.place_order( + account_id=account, + quantity=int(orderObj.get_amount()), + price_type=price_type, + symbol=s, + duration=order.Duration.DAY, + order_type=order_type, + dry_run=orderObj.get_dry(), + ) + print("The order verification produced the following messages: ") + if messages["ORDER CONFIRMATION"] == "No order confirmation page found. Order Failed.": + printAndDiscord("Market order failed placing limit order.", loop) + price_type = order.PriceType.LIMIT + price = vg_order.get_quote(s) + 0.01 + messages = vg_order.place_order( + account_id=account, + quantity=int(orderObj.get_amount()), + price_type=price_type, + symbol=s, + duration=order.Duration.DAY, + order_type=order_type, + limit_price=price, + dry_run=orderObj.get_dry(), + ) + if orderObj.get_dry(): + if messages["ORDER PREVIEW"] != "": + pprint.pprint(messages["ORDER PREVIEW"]) + printAndDiscord( + ( + f"{key} account {print_account}: The order verification was " + + ( + "successful" + if messages["ORDER PREVIEW"] + not in ["", "No order preview page found."] + else "unsuccessful" + ) + ), + loop, + ) + if ( + not messages["ORDER INVALID"] + == "No invalid order message found." + ): + printAndDiscord( + f"{key} account {print_account}: The order verification produced the following messages: {messages['ORDER INVALID']}", + loop, + ) + else: + if messages["ORDER CONFIRMATION"] != "": + pprint.pprint(messages["ORDER CONFIRMATION"]) + printAndDiscord( + ( + f"{key} account {print_account}: The order verification was " + + ( + "successful" + if messages["ORDER CONFIRMATION"] + not in [ + "", + "No order confirmation page found. Order Failed.", + ] + else "unsuccessful" + ) + ), + loop, + ) + if ( + not messages["ORDER INVALID"] + == "No invalid order message found." + ): + printAndDiscord( + f"{key} account {print_account}: The order verification produced the following messages: {messages['ORDER INVALID']}", + loop, + ) + except Exception as e: + printAndDiscord(f"{key} {print_account}: Error submitting order: {e}", loop) + print(traceback.format_exc()) + continue + obj.close_browser() + printAndDiscord( + "All Vanguard transactions complete", + loop, + ) \ No newline at end of file From 9aa5d0535f85fc7fe7f36311defa6b654bb77107 Mon Sep 17 00:00:00 2001 From: maxxrk Date: Sat, 11 May 2024 18:33:54 -0500 Subject: [PATCH 02/24] update vg version --- requirements.txt | 2 +- vanguardAPI.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/requirements.txt b/requirements.txt index 0f864fab..e570d8a6 100644 --- a/requirements.txt +++ b/requirements.txt @@ -11,5 +11,5 @@ requests==2.31.0 schwab-api==0.4.0 selenium==4.20.0 tastytrade==8.0 -vanguard-api==0.0.5 +vanguard-api==0.0.6 -e git+https://github.com/NelsonDane/webull.git@ef14ae63f9e1436fbea77fe864df54847cf2f730#egg=webull diff --git a/vanguardAPI.py b/vanguardAPI.py index a4425d60..f08d7055 100644 --- a/vanguardAPI.py +++ b/vanguardAPI.py @@ -62,7 +62,7 @@ def vanguard_init(account, index, botObj=None, loop=None): debug = bool(account[3]) if len(account) == 4 else False vg_session = session.VanguardSession( title=f"Vanguard_{index}", - headless=False, + headless=True, profile_path="./creds", debug=debug ) From 110b3bc9b44bf6df06783f60c5c556b91c8b7dfa Mon Sep 17 00:00:00 2001 From: maxxrk Date: Fri, 17 May 2024 06:01:09 -0500 Subject: [PATCH 03/24] fix more than one ticker vg --- vanguardAPI.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vanguardAPI.py b/vanguardAPI.py index f08d7055..d39ed2fc 100644 --- a/vanguardAPI.py +++ b/vanguardAPI.py @@ -227,7 +227,7 @@ def vanguard_transaction(vanguard_o: Brokerage, orderObj: stockOrder, loop=None) printAndDiscord(f"{key} {print_account}: Error submitting order: {e}", loop) print(traceback.format_exc()) continue - obj.close_browser() + obj.close_browser() printAndDiscord( "All Vanguard transactions complete", loop, From 0f956eee0b766535ee2a7c1dccab95dd61caf7b8 Mon Sep 17 00:00:00 2001 From: maxxrk Date: Fri, 17 May 2024 06:06:05 -0500 Subject: [PATCH 04/24] use new method for account ids --- vanguardAPI.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/vanguardAPI.py b/vanguardAPI.py index d39ed2fc..9f0bdd8c 100644 --- a/vanguardAPI.py +++ b/vanguardAPI.py @@ -72,13 +72,13 @@ def vanguard_init(account, index, botObj=None, loop=None): vg_session.login_two(input("Enter code: ")) else: sms_code = asyncio.run_coroutine_threadsafe( - getOTPCodeDiscord(botObj, name, code_len=8, loop=loop), loop + getOTPCodeDiscord(botObj, name, timeout=120, loop=loop), loop ).result() if sms_code is None: raise Exception(f"Vanguard {index} code not received in time...", loop) vg_session.login_two(sms_code) all_accounts = vg_account.AllAccount(vg_session) - success = all_accounts.get_holdings() + success = all_accounts.get_account_ids() if success is False: raise Exception("Error getting account details") print("Logged in to Vanguard!") From deb78c959ff3d8433926e0eac2111754895888b4 Mon Sep 17 00:00:00 2001 From: maxxrk Date: Fri, 17 May 2024 20:06:08 -0500 Subject: [PATCH 05/24] bump vg --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index a4e09eed..34289e34 100644 --- a/requirements.txt +++ b/requirements.txt @@ -11,5 +11,5 @@ robin-stocks==3.1.0 schwab-api==0.4.0 selenium==4.20.0 tastytrade==8.0 -vanguard-api==0.0.6 +vanguard-api==0.0.9 -e git+https://github.com/NelsonDane/webull.git@ef14ae63f9e1436fbea77fe864df54847cf2f730#egg=webull From a36d3618a45246c784c6f32d566c24888e5cac60 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 13 May 2024 09:46:26 +0000 Subject: [PATCH 06/24] Bump chaseinvest-api from 0.1.4 to 0.1.5 Bumps [chaseinvest-api](https://github.com/MaxxRK/chaseinvest-api) from 0.1.4 to 0.1.5. - [Release notes](https://github.com/MaxxRK/chaseinvest-api/releases) - [Commits](https://github.com/MaxxRK/chaseinvest-api/compare/v0.1.4...v0.1.5) --- updated-dependencies: - dependency-name: chaseinvest-api dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 34289e34..5b304827 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,5 +1,5 @@ asyncio==3.4.3 -chaseinvest-api==0.1.4 +chaseinvest-api==0.1.5 discord.py==2.3.2 firstrade==0.0.17 GitPython==3.1.43 From 53591f2993b83c40c142aa836c4b363370932ff6 Mon Sep 17 00:00:00 2001 From: Nelson Dane <47427072+NelsonDane@users.noreply.github.com> Date: Mon, 13 May 2024 23:27:42 -0400 Subject: [PATCH 07/24] fix selenium docker on arm --- Dockerfile | 3 ++- fidelityAPI.py | 12 ++++++------ helperAPI.py | 2 +- 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/Dockerfile b/Dockerfile index 8ed63b50..3246ef72 100644 --- a/Dockerfile +++ b/Dockerfile @@ -13,6 +13,7 @@ ENV DISPLAY :99 # Install python, pip, and tzdata RUN apt-get update && apt-get install -y --no-install-recommends \ chromium \ + chromium-driver \ dos2unix \ git \ tzdata \ @@ -24,7 +25,7 @@ COPY ./requirements.txt /app/requirements.txt RUN pip install --no-cache-dir -r /app/requirements.txt # Install playwright -RUN playwright install && \ +RUN playwright install firefox && \ playwright install-deps # CD into app diff --git a/fidelityAPI.py b/fidelityAPI.py index ed4a2012..25b0f78e 100644 --- a/fidelityAPI.py +++ b/fidelityAPI.py @@ -83,16 +83,16 @@ def fidelity_init(FIDELITY_EXTERNAL=None, DOCKER=False): try: WebDriverWait(driver, 10).until( expected_conditions.element_to_be_clickable( - (By.CSS_SELECTOR, "#userId-input") + (By.CSS_SELECTOR, "#dom-username-input") ) ) - username_selector = "#userId-input" - password_selector = "#password" - login_btn_selector = "#fs-login-button" - except TimeoutException: username_selector = "#dom-username-input" password_selector = "#dom-pswd-input" login_btn_selector = "#dom-login-button > div" + except TimeoutException: + username_selector = "#userId-input" + password_selector = "#password" + login_btn_selector = "#fs-login-button" WebDriverWait(driver, 10).until( expected_conditions.element_to_be_clickable( (By.CSS_SELECTOR, username_selector) @@ -109,8 +109,8 @@ def fidelity_init(FIDELITY_EXTERNAL=None, DOCKER=False): driver.find_element(by=By.CSS_SELECTOR, value=login_btn_selector).click() WebDriverWait(driver, 10).until(check_if_page_loaded) sleep(3) - # Retry the login if we get an error page try: + # Look for: Sorry, we can't complete this action right now. Please try again. go_back_selector = "#dom-sys-err-go-to-login-button > span > s-slot > s-assigned-wrapper" WebDriverWait(driver, 10).until( expected_conditions.element_to_be_clickable( diff --git a/helperAPI.py b/helperAPI.py index a2bfb13f..f9419ac9 100644 --- a/helperAPI.py +++ b/helperAPI.py @@ -498,7 +498,7 @@ def getDriver(DOCKER=False): options.add_argument("--disable-gpu") # Docker uses specific chromedriver installed via apt driver = webdriver.Chrome( - service=ChromiumService(), + service=ChromiumService("/usr/bin/chromedriver"), options=options, ) else: From 267ce8e77a611db4d69bb84f975b02630a46095e Mon Sep 17 00:00:00 2001 From: Nelson Dane <47427072+NelsonDane@users.noreply.github.com> Date: Tue, 14 May 2024 00:13:29 -0400 Subject: [PATCH 08/24] fix fidelity symbol not found --- fidelityAPI.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/fidelityAPI.py b/fidelityAPI.py index 25b0f78e..bd713dc3 100644 --- a/fidelityAPI.py +++ b/fidelityAPI.py @@ -310,7 +310,6 @@ def fidelity_transaction(fidelity_o: Brokerage, orderObj: stockOrder, loop=None) by=By.CSS_SELECTOR, value="#ett-acct-sel-list" ) accounts_list = test.find_elements(by=By.CSS_SELECTOR, value="li") - print(f"Number of accounts: {len(accounts_list)}") number_of_accounts = len(accounts_list) # Click a second time to clear the account list driver.execute_script("arguments[0].click();", accounts_dropdown) @@ -354,10 +353,14 @@ def fidelity_transaction(fidelity_o: Brokerage, orderObj: stockOrder, loop=None) try: driver.find_element( by=By.CSS_SELECTOR, - value="body > div.app-body > ap122489-ett-component > div > order-entry > div.eq-ticket.order-entry__container-height > div > div > form > div.order-entry__container-content.scroll > div:nth-child(2) > symbol-search > div > div.eq-ticket--border-top > div > div:nth-child(2) > div > div > div > pvd3-inline-alert > s-root > div > div.pvd-inline-alert__content > s-slot > s-assigned-wrapper", + value="body > div.app-body > ap122489-ett-component > div > order-entry-base > div > div > div.order-entry__container-content.scroll > div > equity-order-selection > div:nth-child(1) > symbol-search > div > div.eq-ticket--border-top > div > div:nth-child(2) > div > div > div > pvd3-inline-alert > s-root > div > div.pvd-inline-alert__content > s-slot > s-assigned-wrapper", ) - print(f"Error: Symbol {s} not found") - return + printAndDiscord( + f"{key} Error: Symbol {s} not found", loop + ) + print() + killSeleniumDriver(fidelity_o) + return None except Exception: pass # Get last price From fc98b40dc4d980b8bef3abab331424e4a7b23f6c Mon Sep 17 00:00:00 2001 From: "deepsource-autofix[bot]" <62050782+deepsource-autofix[bot]@users.noreply.github.com> Date: Tue, 14 May 2024 14:37:20 +0000 Subject: [PATCH 09/24] style: format code with Black and isort This commit fixes the style issues introduced in 122a94a according to the output from Black and isort. Details: None --- fidelityAPI.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/fidelityAPI.py b/fidelityAPI.py index bd713dc3..ab42a40b 100644 --- a/fidelityAPI.py +++ b/fidelityAPI.py @@ -355,9 +355,7 @@ def fidelity_transaction(fidelity_o: Brokerage, orderObj: stockOrder, loop=None) by=By.CSS_SELECTOR, value="body > div.app-body > ap122489-ett-component > div > order-entry-base > div > div > div.order-entry__container-content.scroll > div > equity-order-selection > div:nth-child(1) > symbol-search > div > div.eq-ticket--border-top > div > div:nth-child(2) > div > div > div > pvd3-inline-alert > s-root > div > div.pvd-inline-alert__content > s-slot > s-assigned-wrapper", ) - printAndDiscord( - f"{key} Error: Symbol {s} not found", loop - ) + printAndDiscord(f"{key} Error: Symbol {s} not found", loop) print() killSeleniumDriver(fidelity_o) return None From 711c10c7a858a377946ddcfcb34ee6ee67e7804c Mon Sep 17 00:00:00 2001 From: Nelson Dane <47427072+NelsonDane@users.noreply.github.com> Date: Tue, 14 May 2024 10:40:36 -0400 Subject: [PATCH 10/24] fix no return --- fidelityAPI.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/fidelityAPI.py b/fidelityAPI.py index ab42a40b..30dbc019 100644 --- a/fidelityAPI.py +++ b/fidelityAPI.py @@ -314,9 +314,9 @@ def fidelity_transaction(fidelity_o: Brokerage, orderObj: stockOrder, loop=None) # Click a second time to clear the account list driver.execute_script("arguments[0].click();", accounts_dropdown) except Exception as e: - print(f"Error: No accounts foundin dropdown: {e}") - traceback.print_exc() - return + fidelity_error(driver, f"No accounts found in dropdown: {e}") + killSeleniumDriver(fidelity_o) + return None # Complete on each account # Because of stale elements, we need to re-find the elements each time for x in range(number_of_accounts): From 28efccf9b8fe02eec795071fef64438969d3cbfd Mon Sep 17 00:00:00 2001 From: maxxrk Date: Wed, 15 May 2024 19:59:45 -0500 Subject: [PATCH 11/24] fix multi ticker chase error --- chaseAPI.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/chaseAPI.py b/chaseAPI.py index 1ce18149..fa232336 100644 --- a/chaseAPI.py +++ b/chaseAPI.py @@ -246,11 +246,10 @@ def chase_transaction(chase_o: Brokerage, orderObj: stockOrder, loop=None): loop, ) except Exception as e: - obj.close_browser() printAndDiscord(f"{key} {account}: Error submitting order: {e}", loop) print(traceback.format_exc()) continue - obj.close_browser() + obj.close_browser() printAndDiscord( "All Chase transactions complete", loop, From 60aac60b3f57b2487f9d8ab828d0157bf46395e8 Mon Sep 17 00:00:00 2001 From: Nelson Dane <47427072+NelsonDane@users.noreply.github.com> Date: Fri, 17 May 2024 10:34:30 -0400 Subject: [PATCH 12/24] update chase --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 5b304827..6438ce9a 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,5 +1,5 @@ asyncio==3.4.3 -chaseinvest-api==0.1.5 +chaseinvest-api==0.1.6 discord.py==2.3.2 firstrade==0.0.17 GitPython==3.1.43 From cd15e4b93a1136a5f5934a4e37f61b4c43de1981 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 17 May 2024 14:35:21 +0000 Subject: [PATCH 13/24] Bump selenium from 4.20.0 to 4.21.0 Bumps [selenium](https://github.com/SeleniumHQ/Selenium) from 4.20.0 to 4.21.0. - [Release notes](https://github.com/SeleniumHQ/Selenium/releases) - [Commits](https://github.com/SeleniumHQ/Selenium/compare/selenium-4.20.0...selenium-4.21.0) --- updated-dependencies: - dependency-name: selenium dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 6438ce9a..1905865a 100644 --- a/requirements.txt +++ b/requirements.txt @@ -9,7 +9,7 @@ python-dotenv==1.0.1 requests==2.31.0 robin-stocks==3.1.0 schwab-api==0.4.0 -selenium==4.20.0 +selenium==4.21.0 tastytrade==8.0 vanguard-api==0.0.9 -e git+https://github.com/NelsonDane/webull.git@ef14ae63f9e1436fbea77fe864df54847cf2f730#egg=webull From 6bd140e0a013218fe0c390706412f4d23d57d939 Mon Sep 17 00:00:00 2001 From: maxxrk Date: Mon, 20 May 2024 09:03:46 -0500 Subject: [PATCH 14/24] bump vg version --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 1905865a..4ad596db 100644 --- a/requirements.txt +++ b/requirements.txt @@ -11,5 +11,5 @@ robin-stocks==3.1.0 schwab-api==0.4.0 selenium==4.21.0 tastytrade==8.0 -vanguard-api==0.0.9 +vanguard-api==0.1.0 -e git+https://github.com/NelsonDane/webull.git@ef14ae63f9e1436fbea77fe864df54847cf2f730#egg=webull From 10f942d948c76174496eb16540741d072e4215e0 Mon Sep 17 00:00:00 2001 From: Nelson Dane <47427072+NelsonDane@users.noreply.github.com> Date: Mon, 20 May 2024 14:08:52 -0400 Subject: [PATCH 15/24] don't display 0 holdings --- vanguardAPI.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/vanguardAPI.py b/vanguardAPI.py index 9f0bdd8c..e67e9c89 100644 --- a/vanguardAPI.py +++ b/vanguardAPI.py @@ -79,7 +79,7 @@ def vanguard_init(account, index, botObj=None, loop=None): vg_session.login_two(sms_code) all_accounts = vg_account.AllAccount(vg_session) success = all_accounts.get_account_ids() - if success is False: + if not success: raise Exception("Error getting account details") print("Logged in to Vanguard!") vanguard_obj.set_logged_in_object(name, vg_session) @@ -110,7 +110,8 @@ def vanguard_holdings(vanguard_o: Brokerage, loop=None): for account in all_accounts.accounts_positions.keys(): for type in all_accounts.accounts_positions[account].keys(): for stock in all_accounts.accounts_positions[account][type]: - vanguard_o.set_holdings(key, account, stock["symbol"], stock["quantity"], stock["price"]) + if int(stock["quantity"]) != 0: + vanguard_o.set_holdings(key, account, stock["symbol"], stock["quantity"], stock["price"]) else: raise Exception("Vanguard-api failed to retrieve holdings.") except Exception as e: From a67edd02348f5a19bfa3c18a4c3bd81d11de0ccb Mon Sep 17 00:00:00 2001 From: Nelson Dane <47427072+NelsonDane@users.noreply.github.com> Date: Mon, 20 May 2024 14:18:08 -0400 Subject: [PATCH 16/24] fix fractionals --- vanguardAPI.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vanguardAPI.py b/vanguardAPI.py index e67e9c89..be6171a1 100644 --- a/vanguardAPI.py +++ b/vanguardAPI.py @@ -110,7 +110,7 @@ def vanguard_holdings(vanguard_o: Brokerage, loop=None): for account in all_accounts.accounts_positions.keys(): for type in all_accounts.accounts_positions[account].keys(): for stock in all_accounts.accounts_positions[account][type]: - if int(stock["quantity"]) != 0: + if float(stock["quantity"]) != 0: vanguard_o.set_holdings(key, account, stock["symbol"], stock["quantity"], stock["price"]) else: raise Exception("Vanguard-api failed to retrieve holdings.") From eb21114dfccb6bcfd765b6a1bf0faa7de05b06ff Mon Sep 17 00:00:00 2001 From: Nelson Dane <47427072+NelsonDane@users.noreply.github.com> Date: Wed, 22 May 2024 14:20:59 -0400 Subject: [PATCH 17/24] vg bump --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index ee3f0970..2dd6e019 100644 --- a/requirements.txt +++ b/requirements.txt @@ -11,5 +11,5 @@ robin-stocks==3.1.0 schwab-api==0.4.0 selenium==4.21.0 tastytrade==8.0 -vanguard-api==0.1.0 +vanguard-api==0.1.2 -e git+https://github.com/NelsonDane/webull.git@ef14ae63f9e1436fbea77fe864df54847cf2f730#egg=webull From d6b1039f57123885999481c8c3b30e500c757b73 Mon Sep 17 00:00:00 2001 From: Nelson Dane <47427072+NelsonDane@users.noreply.github.com> Date: Tue, 28 May 2024 21:23:41 -0400 Subject: [PATCH 18/24] vg bump --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 9868e2b1..b9e3c22e 100644 --- a/requirements.txt +++ b/requirements.txt @@ -13,5 +13,5 @@ schwab-api==0.4.0 selenium==4.21.0 setuptools==70.0.0 tastytrade==8.0 -vanguard-api==0.1.2 +vanguard-api==0.1.4 -e git+https://github.com/NelsonDane/webull.git@ef14ae63f9e1436fbea77fe864df54847cf2f730#egg=webull From ce9180707f8b2c78ca6ddc3b3d179a37f8739d87 Mon Sep 17 00:00:00 2001 From: maxxrk Date: Fri, 31 May 2024 11:44:29 -0500 Subject: [PATCH 19/24] vg bump --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index b9e3c22e..8c7809fc 100644 --- a/requirements.txt +++ b/requirements.txt @@ -13,5 +13,5 @@ schwab-api==0.4.0 selenium==4.21.0 setuptools==70.0.0 tastytrade==8.0 -vanguard-api==0.1.4 +vanguard-api==0.1.5 -e git+https://github.com/NelsonDane/webull.git@ef14ae63f9e1436fbea77fe864df54847cf2f730#egg=webull From 53ae523457ceb25878999642f231473858f3c82f Mon Sep 17 00:00:00 2001 From: maxxrk Date: Fri, 31 May 2024 12:36:37 -0500 Subject: [PATCH 20/24] bump vg --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 8c7809fc..8612486e 100644 --- a/requirements.txt +++ b/requirements.txt @@ -13,5 +13,5 @@ schwab-api==0.4.0 selenium==4.21.0 setuptools==70.0.0 tastytrade==8.0 -vanguard-api==0.1.5 +vanguard-api==0.1.6 -e git+https://github.com/NelsonDane/webull.git@ef14ae63f9e1436fbea77fe864df54847cf2f730#egg=webull From 7e7318e1ea89c62db803f546809e9df4bf01630b Mon Sep 17 00:00:00 2001 From: maxxrk Date: Thu, 6 Jun 2024 12:14:05 -0500 Subject: [PATCH 21/24] bump vg --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 906be9d8..127d927d 100644 --- a/requirements.txt +++ b/requirements.txt @@ -13,5 +13,5 @@ schwab-api==0.4.0 selenium==4.21.0 setuptools==70.0.0 tastytrade==8.0 -vanguard-api==0.1.6 +vanguard-api==0.1.7 -e git+https://github.com/NelsonDane/webull.git@ef14ae63f9e1436fbea77fe864df54847cf2f730#egg=webull From 6b8fd8f2f00c32e295c44afadbda5261aa8b17c2 Mon Sep 17 00:00:00 2001 From: "deepsource-autofix[bot]" <62050782+deepsource-autofix[bot]@users.noreply.github.com> Date: Mon, 10 Jun 2024 02:20:11 +0000 Subject: [PATCH 22/24] style: format code with Black and isort This commit fixes the style issues introduced in de11c7e according to the output from Black and isort. Details: None --- vanguardAPI.py | 51 +++++++++++++++++++++++++++++++------------------- 1 file changed, 32 insertions(+), 19 deletions(-) diff --git a/vanguardAPI.py b/vanguardAPI.py index be6171a1..b499c259 100644 --- a/vanguardAPI.py +++ b/vanguardAPI.py @@ -6,9 +6,9 @@ import pprint import traceback +from dotenv import load_dotenv from vanguard import account as vg_account from vanguard import order, session -from dotenv import load_dotenv from helperAPI import ( Brokerage, @@ -20,18 +20,14 @@ ) -def vanguard_run( - orderObj: stockOrder, command=None, botObj=None, loop=None -): +def vanguard_run(orderObj: stockOrder, command=None, botObj=None, loop=None): # Initialize .env file load_dotenv() # Import Vanguard account if not os.getenv("VANGUARD"): print("Vanguard not found, skipping...") return None - accounts = ( - os.environ["VANGUARD"].strip().split(",") - ) + accounts = os.environ["VANGUARD"].strip().split(",") # Set the functions to be run _, second_command = command @@ -64,7 +60,7 @@ def vanguard_init(account, index, botObj=None, loop=None): title=f"Vanguard_{index}", headless=True, profile_path="./creds", - debug=debug + debug=debug, ) need_second = vg_session.login(account[0], account[1], account[2]) if need_second: @@ -75,7 +71,9 @@ def vanguard_init(account, index, botObj=None, loop=None): getOTPCodeDiscord(botObj, name, timeout=120, loop=loop), loop ).result() if sms_code is None: - raise Exception(f"Vanguard {index} code not received in time...", loop) + raise Exception( + f"Vanguard {index} code not received in time...", loop + ) vg_session.login_two(sms_code) all_accounts = vg_account.AllAccount(vg_session) success = all_accounts.get_account_ids() @@ -86,7 +84,9 @@ def vanguard_init(account, index, botObj=None, loop=None): print_accounts = [] for acct in all_accounts.account_totals.keys(): vanguard_obj.set_account_number(name, acct) - vanguard_obj.set_account_totals(name, acct, all_accounts.account_totals[acct]) + vanguard_obj.set_account_totals( + name, acct, all_accounts.account_totals[acct] + ) print_accounts.append(acct) print(f"The following Vanguard accounts were found: {print_accounts}") except Exception as e: @@ -111,7 +111,13 @@ def vanguard_holdings(vanguard_o: Brokerage, loop=None): for type in all_accounts.accounts_positions[account].keys(): for stock in all_accounts.accounts_positions[account][type]: if float(stock["quantity"]) != 0: - vanguard_o.set_holdings(key, account, stock["symbol"], stock["quantity"], stock["price"]) + vanguard_o.set_holdings( + key, + account, + stock["symbol"], + stock["quantity"], + stock["price"], + ) else: raise Exception("Vanguard-api failed to retrieve holdings.") except Exception as e: @@ -161,16 +167,21 @@ def vanguard_transaction(vanguard_o: Brokerage, orderObj: stockOrder, loop=None) dry_run=orderObj.get_dry(), ) print("The order verification produced the following messages: ") - if messages["ORDER CONFIRMATION"] == "No order confirmation page found. Order Failed.": - printAndDiscord("Market order failed placing limit order.", loop) + if ( + messages["ORDER CONFIRMATION"] + == "No order confirmation page found. Order Failed." + ): + printAndDiscord( + "Market order failed placing limit order.", loop + ) price_type = order.PriceType.LIMIT price = vg_order.get_quote(s) + 0.01 messages = vg_order.place_order( account_id=account, - quantity=int(orderObj.get_amount()), - price_type=price_type, - symbol=s, - duration=order.Duration.DAY, + quantity=int(orderObj.get_amount()), + price_type=price_type, + symbol=s, + duration=order.Duration.DAY, order_type=order_type, limit_price=price, dry_run=orderObj.get_dry(), @@ -225,11 +236,13 @@ def vanguard_transaction(vanguard_o: Brokerage, orderObj: stockOrder, loop=None) loop, ) except Exception as e: - printAndDiscord(f"{key} {print_account}: Error submitting order: {e}", loop) + printAndDiscord( + f"{key} {print_account}: Error submitting order: {e}", loop + ) print(traceback.format_exc()) continue obj.close_browser() printAndDiscord( "All Vanguard transactions complete", loop, - ) \ No newline at end of file + ) From abf3a1f3ce884e5fc0930d49ec9bbd84bdcec5e2 Mon Sep 17 00:00:00 2001 From: Nelson Dane <47427072+NelsonDane@users.noreply.github.com> Date: Sun, 9 Jun 2024 22:28:13 -0400 Subject: [PATCH 23/24] deepsource fixes --- vanguardAPI.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/vanguardAPI.py b/vanguardAPI.py index b499c259..89ba58c2 100644 --- a/vanguardAPI.py +++ b/vanguardAPI.py @@ -82,7 +82,7 @@ def vanguard_init(account, index, botObj=None, loop=None): print("Logged in to Vanguard!") vanguard_obj.set_logged_in_object(name, vg_session) print_accounts = [] - for acct in all_accounts.account_totals.keys(): + for acct in all_accounts.account_totals: vanguard_obj.set_account_number(name, acct) vanguard_obj.set_account_totals( name, acct, all_accounts.account_totals[acct] @@ -107,9 +107,9 @@ def vanguard_holdings(vanguard_o: Brokerage, loop=None): raise Exception("Error getting account details") success = all_accounts.get_holdings() if success: - for account in all_accounts.accounts_positions.keys(): - for type in all_accounts.accounts_positions[account].keys(): - for stock in all_accounts.accounts_positions[account][type]: + for account in all_accounts.accounts_positions: + for account_type in all_accounts.accounts_positions[account].keys(): + for stock in all_accounts.accounts_positions[account][account_type]: if float(stock["quantity"]) != 0: vanguard_o.set_holdings( key, @@ -202,8 +202,8 @@ def vanguard_transaction(vanguard_o: Brokerage, orderObj: stockOrder, loop=None) loop, ) if ( - not messages["ORDER INVALID"] - == "No invalid order message found." + messages["ORDER INVALID"] + != "No invalid order message found." ): printAndDiscord( f"{key} account {print_account}: The order verification produced the following messages: {messages['ORDER INVALID']}", @@ -228,8 +228,8 @@ def vanguard_transaction(vanguard_o: Brokerage, orderObj: stockOrder, loop=None) loop, ) if ( - not messages["ORDER INVALID"] - == "No invalid order message found." + messages["ORDER INVALID"] + != "No invalid order message found." ): printAndDiscord( f"{key} account {print_account}: The order verification produced the following messages: {messages['ORDER INVALID']}", From b64e28859b9ff219fbf69e1658ff6eb35edc04d4 Mon Sep 17 00:00:00 2001 From: "deepsource-autofix[bot]" <62050782+deepsource-autofix[bot]@users.noreply.github.com> Date: Mon, 10 Jun 2024 02:28:25 +0000 Subject: [PATCH 24/24] style: format code with Black and isort This commit fixes the style issues introduced in abf3a1f according to the output from Black and isort. Details: https://github.com/NelsonDane/auto-rsa/pull/256 --- vanguardAPI.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/vanguardAPI.py b/vanguardAPI.py index 89ba58c2..ec0cc248 100644 --- a/vanguardAPI.py +++ b/vanguardAPI.py @@ -109,7 +109,9 @@ def vanguard_holdings(vanguard_o: Brokerage, loop=None): if success: for account in all_accounts.accounts_positions: for account_type in all_accounts.accounts_positions[account].keys(): - for stock in all_accounts.accounts_positions[account][account_type]: + for stock in all_accounts.accounts_positions[account][ + account_type + ]: if float(stock["quantity"]) != 0: vanguard_o.set_holdings( key,