Skip to content

Commit

Permalink
changed required Storage Admin to Storage Object Admin IAM role. Upda…
Browse files Browse the repository at this point in the history
…ted exported postman collection containing response examples.
  • Loading branch information
hilliao committed Jun 8, 2023
1 parent 797fe1b commit e1a170c
Show file tree
Hide file tree
Showing 7 changed files with 178 additions and 29 deletions.
11 changes: 10 additions & 1 deletion googlecloud/smart-invest/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,4 +44,13 @@ in stepping through the code. Refer to the screenshot of PyCharm's run,debug con
Basically, in run,debug configuration, under configuration, change from script path to module name. Click on the
3 dots to locate the functions-framework module. You'd need to type it to check if it exists. Enter the parameters:
--target stock_quotes --port 8081 --debug where stock_quotes is the function name and 8081 is an unused port on local.
Set the working directory to the directory of the function's filename.
Set the working directory to the directory of the function's filename.

### Environment Variables
* BUCKET=[Created bucket name to store stock quotes]
* FOLDER=[GSC bucket's folder to store quote .json files]
* PROJECT_ID=[Google Cloud Project ID]
* SECRET_MANAGER_PROJECT_ID=[Project ID for secret manager]
* SECRET_NAME_CLIENT_ID_SECRET=[Secret manager's secret name that stores Trade Station's client ID and secret separated by ,]
* SECRET_NAME_REFRESH_TOKEN=[Secret manager's secret name that stores Trade Station's refresh token]
* SECRET_NAME_YH_API_KEY=[Secret manager's secret name that stores the Yahoo Finance API key]
3 changes: 3 additions & 0 deletions googlecloud/smart-invest/cloud-function/algo_trade.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,10 @@ def recommend(amplify: float, intended_allocation: dict, quotes: dict):
# assign the Exception to trade dictionary's value for later processing
trades[ticker] = quotes[ticker]
continue
# Only the Yahoo Finance cached quotes have 50 and 200 day moving averages
# If the cloud scheduler execution does not contain the stock ticker, the method would return None
if not quotes[ticker].diff_price_average():
# Make the return dict have values of Exceptions for later HTTP response
trades[ticker] = Exception("Failed to get fiftyDayAverage or twoHundredDayAverage from cached quotes")
continue

Expand Down
16 changes: 13 additions & 3 deletions googlecloud/smart-invest/cloud-function/brokerage.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,9 +53,11 @@ def latest_ticker_price(self):
return None


# try to get the cached Yahoo Finance quotes first. If no cached quotes, return the trade station quotes.
# If both quotes exist, the keys in trade station quotes would override the key,value items from Yahoo Finance quotes.
def get_cached_or_realtime_quote(bucket, ticker):
storage_client = storage.Client()
bucket = storage_client.get_bucket(bucket)
bucket = storage_client.bucket(bucket)
gcs_path = "{0}/{1}.json".format(os.environ.get('FOLDER'), ticker)
blob = bucket.blob(gcs_path)
try:
Expand Down Expand Up @@ -139,6 +141,8 @@ def refresh_access_token():
MAX_WORKERS = 10


# Cached quotes are from Yahoo Finance where twoHundredDayAverage and fiftyDayAverage keys exist.
# Real time quotes from trade station don't have those averages.
def get_cached_or_realtime_quotes(bucket, tickers):
thread_results = {}
with ThreadPoolExecutor(max_workers=int(MAX_WORKERS)) as executor:
Expand All @@ -157,11 +161,14 @@ def get_cached_or_realtime_quotes(bucket, tickers):
return thread_results


# limit_order_off is how much less than the quoted price for a limit trade order. 0.1 means for a quoted stock that's
# $100, the limit order is set at $90. Generally, you'd want to set the price to be less than the quoted price.
def execute_trade_order(trade_orders: dict, account_id: str, duration: str = 'GTC', limit_order_off: float = 0.01):
# API doc: https://api.tradestation.com/docs/specification/#operation/ConfirmGroupOrder
trade_station_order_api = "{}/orderexecution/ordergroups".format(trade_station_url)

orders = []
# trade_orders dict may have values of Exceptions where recommendations failed
for ticker, order in trade_orders.items():
if isinstance(order, Exception):
continue
Expand Down Expand Up @@ -209,8 +216,11 @@ def execute_trade_order(trade_orders: dict, account_id: str, duration: str = 'GT

def yh_finance_get_quotes(tickers):
yh_finance_url = "https://yh-finance.p.rapidapi.com/market/v2/get-quotes"
querystring = {"region": "US",
"symbols": tickers} # "QQQ,ONEQ,IVV,VOO,JETS,VHT,VDE,VFH,VTWO,BRK-B,ACN,AMD,GOOGL,AMZN,MSFT,MRVL,FB,QCOM,CRM,SNAP,TSM,BHP,RIO,EXPE,BKNG,HD"
# example: "QQQ,ONEQ,IVV,VOO,JETS,VHT,VDE,VFH,VTWO,BRK-B,ACN,AMD,GOOGL,AMZN,MSFT,MRVL,FB,QCOM,CRM,SNAP,TSM,BHP,RIO,EXPE,BKNG,HD"
querystring = {
"region": "US",
"symbols": tickers
}
env_var_secret_name = 'SECRET_NAME_YH_API_KEY'
YH_API_key = get_secret_value(env_var_secret_name)
headers = {
Expand Down
14 changes: 8 additions & 6 deletions googlecloud/smart-invest/cloud-function/cloud_native.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,12 +39,14 @@ def insert_to_bq(bq_table: str, trades: dict, account: int = -1):
if isinstance(order, Exception):
continue
rows_to_insert.append(
{"account": account,
"ticker": ticker,
"cash": order.cash,
"price": order.price,
"shares": order.shares,
"updated": recommended_timestamp}
{
"account": account,
"ticker": ticker,
"cash": order.cash,
"price": order.price,
"shares": order.shares,
"updated": recommended_timestamp
}
)
client = bigquery.Client()
try:
Expand Down
Loading

0 comments on commit e1a170c

Please sign in to comment.