You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
I tried this example and it didn't work initially, but I fixed it. I'm sharing it with you. Lumibot is a great tool.
Thanks!
from datetime import datetime
from lumibot.strategies.strategy import Strategy
"""
Strategy Description
Buys the best performing asset from self.symbols over self.period number of days.
For example, if SPY increased 2% yesterday, but VEU and AGG only increased 1% yesterday,
then we will buy SPY.
"""
class Momentum(Strategy):
# =====Overloading lifecycle methods=============
def initialize(self, symbols=None):
# Setting the waiting period (in days)
self.period = 2
# The counter for the number of days we have been holding the current asset
self.counter = 0
# There is only one trading operation per day
# No need to sleep between iterations
self.sleeptime = 0
# Set the symbols that we will be monitoring for momentum
if symbols:
self.symbols = symbols
else:
self.symbols = ["SPY", "VEU", "AGG"]
# The asset that we want to buy/currently own, and the quantity
self.asset = ""
self.quantity = 0
def on_trading_iteration(self):
# When the counter reaches the desired holding period,
# re-evaluate which asset we should be holding
momentums = []
if self.counter == self.period or self.counter == 0:
self.counter = 0
momentums = self.get_assets_momentums()
# Get the asset with the highest return in our period
# (aka the highest momentum)
momentums.sort(key=lambda x: x.get("return"))
best_asset_data = momentums[-1]
best_asset = best_asset_data["symbol"]
best_asset_return = best_asset_data["return"]
# Get the data for the currently held asset
if self.asset:
current_asset_data = [
m for m in momentums if m["symbol"] == self.asset
][0]
current_asset_return = current_asset_data["return"]
# If the returns are equals, keep the current asset
if current_asset_return >= best_asset_return:
best_asset = self.asset
best_asset_data = current_asset_data
self.log_message("%s best symbol." % best_asset)
# If the asset with the highest momentum has changed, buy the new asset
if best_asset != self.asset:
# Sell the current asset that we own
if self.asset:
self.log_message("Swapping %s for %s." % (self.asset, best_asset))
order = self.create_order(self.asset, self.quantity, "sell")
self.submit_order(order)
# Calculate the quantity and send the buy order for the new asset
self.asset = best_asset
best_asset_price = best_asset_data["price"]
self.quantity = int(self.portfolio_value // best_asset_price)
order = self.create_order(self.asset, self.quantity, "buy")
self.submit_order(order)
else:
self.log_message("Keeping %d shares of %s" % (self.quantity, self.asset))
self.counter += 1
# Stop for the day, since we are looking at daily momentums
self.await_market_to_close()
def on_abrupt_closing(self):
# Sell all positions
self.sell_all()
def trace_stats(self, context, snapshot_before):
"""
Add additional stats to the CSV logfile
"""
# Get the values of all our variables from the last iteration
row = {
"old_best_asset": snapshot_before.get("asset"),
"old_asset_quantity": snapshot_before.get("quantity"),
"old_cash": snapshot_before.get("cash"),
"new_best_asset": self.asset,
"new_asset_quantity": self.quantity,
}
# Get the momentums of all the assets from the context of on_trading_iteration
# (notice that on_trading_iteration has a variable called momentums, this is what
# we are reading here)
momentums = context.get("momentums")
if len(momentums) != 0:
for item in momentums:
symbol = item.get("symbol")
for key in item:
if key != "symbol":
row[f"{symbol}_{key}"] = item[key]
# Add all of our values to the row in the CSV file. These automatically get
# added to portfolio_value, cash and return
return row
# =============Helper methods====================
def get_assets_momentums(self):
"""
Gets the momentums (the percentage return) for all the assets we are tracking,
over the time period set in self.period
"""
momentums = []
data = self.get_historical_prices_for_assets(self.symbols, self.period + 2, timestep="day")
# data = self.get_bars(self.symbols, self.period + 2, timestep="day")
for asset, bars_set in data.items():
# Get the return for symbol over self.period days
symbol = asset.symbol
symbol_momentum = bars_set.get_momentum(end=self.period)
self.log_message(
"%s has a return value of %.2f%% over the last %d day(s)."
% (symbol, 100 * symbol_momentum, self.period)
)
momentums.append(
{
"symbol": symbol,
"price": bars_set.get_last_price(),
"return": symbol_momentum,
}
)
return momentums
if name == "main":
is_live = False
if is_live:
from credentials import ALPACA_CONFIG
from lumibot.brokers import Alpaca
from lumibot.traders import Trader
trader = Trader()
broker = Alpaca(ALPACA_CONFIG)
strategy = Momentum(broker=broker)
trader.add_strategy(strategy)
strategy_executors = trader.run_all()
else:
from lumibot.backtesting import YahooDataBacktesting
# Backtest this strategy
backtesting_start = datetime(2023, 1, 1)
backtesting_end = datetime(2024, 8, 1)
results = Momentum.backtest(
YahooDataBacktesting,
backtesting_start,
backtesting_end,
benchmark_asset="SPY",
logfile="./log.txt",
)
hey thanks @pabloadmin !
so what exactly was the issue? and how were you running it to get the problem? it works fine in render and on my local computer
Hi, i used the requirements.txt that appear in root github repository to install all libraries, but the code didn't work.
Maybe was a differents versions of libraries, different functions parameters, at this line made a change in the nema of parameter:
Hi,
I tried this example and it didn't work initially, but I fixed it. I'm sharing it with you. Lumibot is a great tool.
Thanks!
from datetime import datetime
from lumibot.strategies.strategy import Strategy
"""
Strategy Description
Buys the best performing asset from self.symbols over self.period number of days.
For example, if SPY increased 2% yesterday, but VEU and AGG only increased 1% yesterday,
then we will buy SPY.
"""
class Momentum(Strategy):
# =====Overloading lifecycle methods=============
if name == "main":
is_live = False
#############################################################
requirements.txt
aiodns==3.2.0
aiohappyeyeballs==2.4.3
aiohttp==3.11.6
aiosignal==1.3.1
alpaca-py==0.33.0
alpha_vantage==3.0.0
annotated-types==0.7.0
appdirs==1.4.4
APScheduler==3.10.4
asttokens==2.4.1
async-timeout==5.0.1
attrs==24.2.0
bcrypt==4.2.1
beautifulsoup4==4.12.3
bidict==0.23.1
blinker==1.9.0
ccxt==4.2.85
certifi==2024.8.30
cffi==1.15.0
charset-normalizer==3.4.0
click==8.1.7
colorama==0.4.6
contourpy==1.3.0
cryptography==43.0.3
cycler==0.12.1
decorator==5.1.1
dnspython==2.7.0
duckdb==1.1.3
email_validator==2.2.0
exceptiongroup==1.2.2
exchange_calendars==4.5.6
executing==2.1.0
Flask==3.1.0
Flask-Login==0.6.3
flask-marshmallow==1.2.1
Flask-Principal==0.4.0
Flask-Security==5.5.2
Flask-SocketIO==5.4.1
Flask-SQLAlchemy==3.1.1
Flask-WTF==1.2.2
fonttools==4.55.0
frozendict==2.4.6
frozenlist==1.5.0
greenlet==3.1.1
h11==0.14.0
holidays==0.53
html5lib==1.1
ibapi==9.81.1.post1
idna==3.10
ijson==3.3.0
importlib_metadata==8.5.0
importlib_resources==6.4.5
inflection==0.5.1
iniconfig==2.0.0
ipython==8.29.0
itsdangerous==2.2.0
jedi==0.19.2
Jinja2==3.1.4
jsonpickle==4.0.0
kiwisolver==1.4.6
korean-lunar-calendar==0.3.1
lumibot==3.3.1
lumiwealth-tradier==0.1.12
lxml==5.3.0
MarkupSafe==3.0.2
marshmallow==3.23.1
marshmallow-sqlalchemy==1.1.0
matplotlib==3.9.2
matplotlib-inline==0.1.7
more-itertools==10.5.0
msgpack==1.1.0
multidict==6.1.0
multitasking==0.0.11
numpy==1.26.4
packaging==24.2
pandas==2.2.2
pandas-datareader==0.10.0
pandas_market_calendars==4.4.2
parso==0.8.4
passlib==1.7.4
peewee==3.17.8
pillow==10.4.0
platformdirs==4.3.6
plotly==5.24.1
pluggy==1.5.0
polygon-api-client==1.14.2
prompt_toolkit==3.0.48
propcache==0.2.0
psutil==6.1.0
psycopg2-binary==2.9.10
pure_eval==0.2.3
pyarrow==18.0.0
pycares==4.4.0
pycparser==2.22
pydantic==2.0.3
pydantic_core==2.3.0
Pygments==2.18.0
pyluach==2.2.0
pyOpenSSL==22.0.0
pyopenssl-sdk==0.0.0.post0
pyparsing==3.2.0
pytest==8.3.3
python-dateutil==2.9.0.post0
python-dotenv==1.0.1
python-engineio==4.10.1
python-socketio==5.11.4
pytz==2024.2
Quandl==3.7.0
quantstats-lumi==0.3.3
requests==2.32.3
scipy==1.10.1
seaborn==0.13.2
simple-websocket==1.1.0
six==1.16.0
soupsieve==2.6
SQLAlchemy==2.0.36
sseclient-py==1.8.0
stack-data==0.6.3
tabulate==0.9.0
tenacity==9.0.0
termcolor==2.5.0
thetadata==0.9.11
tomli==2.1.0
toolz==1.0.0
tqdm==4.67.0
traitlets==5.14.3
typing_extensions==4.12.2
tzdata==2024.2
tzlocal==5.2
urllib3==2.2.3
uuid==1.30
wcwidth==0.2.13
webencodings==0.5.1
websocket-client==1.8.0
websockets==12.0
Werkzeug==3.1.3
wget==3.2
wsproto==1.2.0
WTForms==3.2.1
yarl==1.17.2
yfinance==0.2.50
zipp==3.21.0
The text was updated successfully, but these errors were encountered: