I've been trying to develop a trading bot using AWS Lambda, DynamoDB, and Eventbridge. However, I've been running into some weird issues with trying to run the test environment in order to ensure that my code works. I'm quite new to the AWS environment and would appreciate any help I can get.
I am trying to let AWS Lambda invoke the lambda_hander
by using the default parameters, here is a snippet of my lambda_handler
for reference.
import os
import boto3
import ctypes
import logging
from datetime import datetime
from datetime import timedelta
from config import ALPACA_CONFIG
import requests
# Handle fast str -> float conversion
def fast_atof(s) -> float:
return ctypes.c_float(float(s)).value
def get_current_asset_position(ticker: str) -> dict:
url = f'https://paper-api.alpaca.markets/v2/positions/{ticker}'
headers = {
"accept": "application/json",
"content-type": "application/json",
"APCA-API-KEY-ID": ALPACA_CONFIG['API_KEY'],
"APCA-API-SECRET-KEY": ALPACA_CONFIG['API_SECRET']
}
asset = requests.get(url, headers=headers)
return asset
def lambda_handler(event, context):
url = "https://paper-api.alpaca.markets/v2/orders"
ticker = "AAPL"
yesterday = str(datetime.today() - timedelta(days = 1))
dynamodb = boto3.resource("dynamodb")
dynamodb.Table("woolyquant_cria_trading_bot")
dynamodb_item = dynamodb.get_item(
Key = {
'Date': yesterday[0:10],
'TickerSymbol': ticker,
}
)
alpaca_headers = {
"accept": "application/json",
"content-type": "application/json",
"APCA-API-KEY-ID": ALPACA_CONFIG['API_KEY'],
"APCA-API-SECRET-KEY": ALPACA_CONFIG['API_SECRET']
}
alpaca_payload = {
"symbol": "AAPL",
"notional": "string",
"type": "stop",
"time_in_force": "day",
"limit_price": "string",
"stop_price": "string",
"trail_price": "string",
"trail_percent": "string",
"extended_hours": False,
}
asset = get_current_asset_position(ticker=ticker)
prev_closing_price = fast_atof(dynamodb_item['ClosingPrice'])
curr_price = fast_atof(asset['current_price'])
if curr_price > prev_closing_price * 1.05:
alpaca_payload['qty'] = asset['qty']
alpaca_payload['side'] = 'sell'
response = requests.post(url, json=alpaca_payload, headers=alpaca_headers)
return response
if curr_price < prev_closing_price * 0.8995:
alpaca_payload['qty'] = '10'
alpaca_payload['side'] = 'buy'
response = requests.post(url, json=alpaca_payload, headers=alpaca_headers)
return response
However, upon running the code in the test environment, it still invokes this error:
{
"errorMessage": "lambda_handler() missing 2 required positional arguments: 'event' and 'context'",
"errorType": "TypeError",
"requestId": "",
"stackTrace": [
" File \"/var/lang/lib/python3.11/importlib/__init__.py\", line 126, in import_module\n return _bootstrap._gcd_import(name[level:], package, level)\n",
" File \"<frozen importlib._bootstrap>\", line 1204, in _gcd_import\n",
" File \"<frozen importlib._bootstrap>\", line 1176, in _find_and_load\n",
" File \"<frozen importlib._bootstrap>\", line 1147, in _find_and_load_unlocked\n",
" File \"<frozen importlib._bootstrap>\", line 690, in _load_unlocked\n",
" File \"<frozen importlib._bootstrap_external>\", line 940, in exec_module\n",
" File \"<frozen importlib._bootstrap>\", line 241, in _call_with_frames_removed\n",
" File \"/var/task/lambda_function.py\", line 80, in <module>\n lambda_handler()\n"
]
}
[ERROR] TypeError: lambda_handler() missing 2 required positional arguments: 'event' and 'context'
Traceback (most recent call last):
File "/var/lang/lib/python3.11/importlib/__init__.py", line 126, in import_module
return _bootstrap._gcd_import(name[level:], package, level)
File "<frozen importlib._bootstrap>", line 1204, in _gcd_import
File "<frozen importlib._bootstrap>", line 1176, in _find_and_load
File "<frozen importlib._bootstrap>", line 1147, in _find_and_load_unlocked
File "<frozen importlib._bootstrap>", line 690, in _load_unlocked
File "<frozen importlib._bootstrap_external>", line 940, in exec_module
File "<frozen importlib._bootstrap>", line 241, in _call_with_frames_removed
File "/var/task/lambda_function.py", line 80, in <module>
lambda_handler()INIT_REPORT Init Duration: 438.31 ms Phase: init Status: error Error Type: Runtime.ExitError
[ERROR] TypeError: lambda_handler() missing 2 required positional arguments: 'event' and 'context'
Traceback (most recent call last):
File "/var/lang/lib/python3.11/importlib/__init__.py", line 126, in import_module
return _bootstrap._gcd_import(name[level:], package, level)
File "<frozen importlib._bootstrap>", line 1204, in _gcd_import
File "<frozen importlib._bootstrap>", line 1176, in _find_and_load
File "<frozen importlib._bootstrap>", line 1147, in _find_and_load_unlocked
File "<frozen importlib._bootstrap>", line 690, in _load_unlocked
File "<frozen importlib._bootstrap_external>", line 940, in exec_module
File "<frozen importlib._bootstrap>", line 241, in _call_with_frames_removed
File "/var/task/lambda_function.py", line 80, in <module>
lambda_handler()INIT_REPORT Init Duration: 5938.52 ms Phase: invoke Status: error Error Type: Runtime.ExitError
START RequestId: cae6b59d-588d-4623-a86c-043ac19e111a Version: $LATEST
Unknown application error occurred
Runtime.Unknown
END RequestId: cae6b59d-588d-4623-a86c-043ac19e111a
REPORT RequestId: cae6b59d-588d-4623-a86c-043ac19e111a Duration: 6070.53 ms Billed Duration: 6071 ms Memory Size: 128 MB Max Memory Used: 27 MB
How I have tried resolving the problem.
However, the issue still persists, and I'm not sure what to do.
There seems to be a lot of issues here, providing your entire Lambda function and not just the handler will help.
It states context and event are missing, even though I see them in your code, which leads me to believe something else is wrong.
You don't show your imports but it's clear you're using the requests
library. Lambda doesn't come bundled with that library by default, so you either use a Lambda Layer or import it from botocore: from botocore.vendored import requests
I tested your code, obviously I had some issue with importing config, which is either in your package or Lambda layer. You had more issues with your DynamoDB setup which I fixed. So you just need to be sure you can import your config and things should work:
import os
import boto3
import ctypes
import logging
from datetime import datetime
from datetime import timedelta
# from config import ALPACA_CONFIG
from botocore.vendored import requests
# Handle fast str -> float conversion
def fast_atof(s) -> float:
return ctypes.c_float(float(s)).value
def get_current_asset_position(ticker: str) -> dict:
url = f'https://paper-api.alpaca.markets/v2/positions/{ticker}'
headers = {
"accept": "application/json",
"content-type": "application/json",
"APCA-API-KEY-ID": ALPACA_CONFIG['API_KEY'],
"APCA-API-SECRET-KEY": ALPACA_CONFIG['API_SECRET']
}
asset = requests.get(url, headers=headers)
return asset
def lambda_handler(event, context):
url = "https://paper-api.alpaca.markets/v2/orders"
ticker = "AAPL"
yesterday = str(datetime.today() - timedelta(days = 1))
dynamodb = boto3.resource("dynamodb")
table = dynamodb.Table("woolyquant_cria_trading_bot")
dynamodb_item = table.get_item(
Key = {
'Date': yesterday[0:10],
'TickerSymbol': ticker,
}
)
alpaca_headers = {
"accept": "application/json",
"content-type": "application/json",
"APCA-API-KEY-ID": ALPACA_CONFIG['API_KEY'],
"APCA-API-SECRET-KEY": ALPACA_CONFIG['API_SECRET']
}
alpaca_payload = {
"symbol": "AAPL",
"notional": "string",
"type": "stop",
"time_in_force": "day",
"limit_price": "string",
"stop_price": "string",
"trail_price": "string",
"trail_percent": "string",
"extended_hours": False,
}
asset = get_current_asset_position(ticker=ticker)
prev_closing_price = fast_atof(dynamodb_item['ClosingPrice'])
curr_price = fast_atof(asset['current_price'])
if curr_price > prev_closing_price * 1.05:
alpaca_payload['qty'] = asset['qty']
alpaca_payload['side'] = 'sell'
response = requests.post(url, json=alpaca_payload, headers=alpaca_headers)
return response
if curr_price < prev_closing_price * 0.8995:
alpaca_payload['qty'] = '10'
alpaca_payload['side'] = 'buy'
response = requests.post(url, json=alpaca_payload, headers=alpaca_headers)
return response