-
-
Notifications
You must be signed in to change notification settings - Fork 45
/
publicAPI.py
148 lines (140 loc) · 5.58 KB
/
publicAPI.py
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
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
import asyncio
import os
import traceback
from dotenv import load_dotenv
from public_invest_api import Public
from helperAPI import (
Brokerage,
getOTPCodeDiscord,
maskString,
printAndDiscord,
printHoldings,
stockOrder,
)
def public_init(PUBLIC_EXTERNAL=None, botObj=None, loop=None):
# Initialize .env file
load_dotenv()
# Import Public account
public_obj = Brokerage("Public")
if not os.getenv("PUBLIC_BROKER") and PUBLIC_EXTERNAL is None:
print("Public not found, skipping...")
return None
PUBLIC = (
os.environ["PUBLIC_BROKER"].strip().split(",")
if PUBLIC_EXTERNAL is None
else PUBLIC_EXTERNAL.strip().split(",")
)
# Log in to Public account
print("Logging in to Public...")
for index, account in enumerate(PUBLIC):
name = f"Public {index + 1}"
try:
account = account.split(":")
pb = Public(filename=f"public{index + 1}.pkl", path="./creds/")
try:
if botObj is None and loop is None:
# Login from CLI
pb.login(
username=account[0],
password=account[1],
wait_for_2fa=True,
)
else:
# Login from Discord and check for 2fa required message
pb.login(
username=account[0],
password=account[1],
wait_for_2fa=False,
)
except Exception as e:
if "2FA" in str(e) and botObj is not None and loop is not None:
# Sometimes codes take a long time to arrive
timeout = 300 # 5 minutes
sms_code = asyncio.run_coroutine_threadsafe(
getOTPCodeDiscord(botObj, name, timeout=timeout, loop=loop),
loop,
).result()
if sms_code is None:
raise Exception("No SMS code found")
pb.login(
username=account[0],
password=account[1],
wait_for_2fa=False,
code=sms_code,
)
else:
raise e
# Public only has one account
public_obj.set_logged_in_object(name, pb)
an = pb.get_account_number()
public_obj.set_account_number(name, an)
print(f"{name}: Found account {maskString(an)}")
atype = pb.get_account_type()
public_obj.set_account_type(name, an, atype)
cash = pb.get_account_cash()
public_obj.set_account_totals(name, an, cash)
except Exception as e:
print(f"Error logging in to Public: {e}")
print(traceback.format_exc())
continue
print("Logged in to Public!")
return public_obj
def public_holdings(pbo: Brokerage, loop=None):
for key in pbo.get_account_numbers():
for account in pbo.get_account_numbers(key):
obj: Public = pbo.get_logged_in_objects(key)
try:
# Get account holdings
positions = obj.get_positions()
if positions != []:
for holding in positions:
# Get symbol, quantity, and total value
sym = holding["instrument"]["symbol"]
qty = float(holding["quantity"])
try:
current_price = obj.get_symbol_price(sym)
except Exception:
current_price = "N/A"
pbo.set_holdings(key, account, sym, qty, current_price)
except Exception as e:
printAndDiscord(f"{key}: Error getting account holdings: {e}", loop)
traceback.format_exc()
continue
printHoldings(pbo, loop)
def public_transaction(pbo: Brokerage, orderObj: stockOrder, loop=None):
print()
print("==============================")
print("Public")
print("==============================")
print()
for s in orderObj.get_stocks():
for key in pbo.get_account_numbers():
printAndDiscord(
f"{key}: {orderObj.get_action()}ing {orderObj.get_amount()} of {s}",
loop,
)
for account in pbo.get_account_numbers(key):
obj: Public = pbo.get_logged_in_objects(key)
print_account = maskString(account)
try:
order = obj.place_order(
symbol=s,
quantity=orderObj.get_amount(),
side=orderObj.get_action(),
order_type="market",
time_in_force="day",
is_dry_run=orderObj.get_dry(),
)
if order["success"] is True:
order = "Success"
dry_message = ""
if orderObj.get_dry():
dry_message = "DRY RUN: "
printAndDiscord(
f"{dry_message}{orderObj.get_action()} {orderObj.get_amount()} of {s} in {print_account}: {order}",
loop,
)
except Exception as e:
printAndDiscord(f"{print_account}: Error placing order: {e}", loop)
traceback.print_exc()
continue