Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29,898 changes: 29,898 additions & 0 deletions logs/MLTrader_2024-04-13_03-47-40_logs.csv

Large diffs are not rendered by default.

1,221 changes: 1,221 additions & 0 deletions logs/MLTrader_2024-04-13_03-47-40_stats.csv

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions logs/MLTrader_2024-04-13_04-24-39_settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"name": "MLTrader", "backtesting_start": {"py/object": "datetime.datetime", "__reduce__": [{"py/type": "datetime.datetime"}, ["B+QBAQAAAAAAAA==", {"py/reduce": [{"py/function": "pytz._p"}, {"py/tuple": ["America/New_York", -18000, 0, "EST"]}]}]]}, "backtesting_end": {"py/object": "datetime.datetime", "__reduce__": [{"py/type": "datetime.datetime"}, ["B+cMHhc7AAAAAA==", {"py/id": 2}]]}, "budget": 100000, "risk_free_rate": {"py/reduce": [{"py/function": "numpy.core.multiarray.scalar"}, {"py/tuple": [{"py/reduce": [{"py/type": "numpy.dtype"}, {"py/tuple": ["f8", false, true]}, {"py/tuple": [3, "<", null, null, null, -1, -1, 0]}]}, {"py/b64": "9ihcj57Nqj8="}]}]}, "minutes_before_closing": 1, "minutes_before_opening": 60, "sleeptime": "24H", "auto_adjust": false, "quote_asset": {"py/object": "lumibot.entities.asset.Asset", "symbol": "USD", "asset_type": "forex", "strike": 0.0, "multiplier": 1, "precision": null, "expiration": null}, "benchmark_asset": "SPY", "starting_positions": null, "parameters": {"pandas_data": null, "symbol": "SPY", "cash_at_risk": 0.5}}
18,050 changes: 18,050 additions & 0 deletions logs/MLTrader_2024-04-13_18-15-04_logs.csv

Large diffs are not rendered by default.

736 changes: 736 additions & 0 deletions logs/MLTrader_2024-04-13_18-15-04_stats.csv

Large diffs are not rendered by default.

29,894 changes: 29,894 additions & 0 deletions logs/MLTrader_2024-04-13_18-28-07_logs.csv

Large diffs are not rendered by default.

1,221 changes: 1,221 additions & 0 deletions logs/MLTrader_2024-04-13_18-28-07_stats.csv

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions logs/MLTrader_2024-04-13_18-46-50_settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"name": "MLTrader", "backtesting_start": {"py/object": "datetime.datetime", "__reduce__": [{"py/type": "datetime.datetime"}, ["B+QBAQAAAAAAAA==", {"py/reduce": [{"py/function": "pytz._p"}, {"py/tuple": ["America/New_York", -18000, 0, "EST"]}]}]]}, "backtesting_end": {"py/object": "datetime.datetime", "__reduce__": [{"py/type": "datetime.datetime"}, ["B+cMHhc7AAAAAA==", {"py/id": 2}]]}, "budget": 100000, "risk_free_rate": {"py/reduce": [{"py/function": "numpy.core.multiarray.scalar"}, {"py/tuple": [{"py/reduce": [{"py/type": "numpy.dtype"}, {"py/tuple": ["f8", false, true]}, {"py/tuple": [3, "<", null, null, null, -1, -1, 0]}]}, {"py/b64": "9ihcj57Nqj8="}]}]}, "minutes_before_closing": 1, "minutes_before_opening": 60, "sleeptime": "24H", "auto_adjust": false, "quote_asset": {"py/object": "lumibot.entities.asset.Asset", "symbol": "USD", "asset_type": "forex", "strike": 0.0, "multiplier": 1, "precision": null, "expiration": null}, "benchmark_asset": "SPY", "starting_positions": null, "parameters": {"pandas_data": null, "symbol": "ASML", "cash_at_risk": 0.5}}
64 changes: 64 additions & 0 deletions test_tradingbot.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import unittest
from unittest.mock import MagicMock

class TestMLTrader(unittest.TestCase):

def setUp(self):
self.trader = MLTrader()

def test_position_sizing(self):
self.trader.get_cash = MagicMock(return_value=10000)
self.trader.get_last_price = MagicMock(return_value=200)
self.trader.calculate_atr = MagicMock(return_value=10)

cash, last_price, quantity, take_profit, stop_loss = self.trader.position_sizing()

self.assertEqual(cash, 10000)
self.assertEqual(last_price, 200)
self.assertEqual(quantity, 25)
self.assertEqual(take_profit, 220)
self.assertEqual(stop_loss, 180)

def test_get_dates(self):
self.trader.get_datetime = MagicMock(return_value=pd.Timestamp('2022-01-01'))
today, three_days_prior = self.trader.get_dates()

self.assertEqual(today, '2022-01-01')
self.assertEqual(three_days_prior, '2021-12-29')

def test_get_sentiment(self):
self.trader.get_dates = MagicMock(return_value=('2022-01-01', '2021-12-29'))
self.trader.api.get_news = MagicMock(return_value=['News 1', 'News 2'])
estimate_sentiment = MagicMock(return_value=(0.8, 'positive'))

with patch('__main__.estimate_sentiment', estimate_sentiment):
probability, sentiment = self.trader.get_sentiment()

self.assertEqual(probability, 0.8)
self.assertEqual(sentiment, 'positive')

def test_on_trading_iteration(self):
self.trader.get_cash = MagicMock(return_value=10000)
self.trader.get_last_price = MagicMock(return_value=200)
self.trader.position_sizing = MagicMock(return_value=(10000, 200, 25, 220, 180))
self.trader.get_sentiment = MagicMock(return_value=(0.8, 'positive'))
self.trader.last_trade = "sell"
self.trader.sell_all = MagicMock()
self.trader.create_order = MagicMock()
self.trader.submit_order = MagicMock()

self.trader.on_trading_iteration()

self.trader.sell_all.assert_called_once()
self.trader.create_order.assert_called_once_with(
self.trader.symbol,
25,
"buy",
type="bracket",
take_profit_price=220,
stop_loss_price=180
)
self.trader.submit_order.assert_called_once()

if __name__ == '__main__':
unittest.main()
76 changes: 44 additions & 32 deletions tradingbot.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@
from finbert_utils import estimate_sentiment

API_KEY = "YOUR API KEY"
API_SECRET = "YOUR API SECRET"
BASE_URL = "https://paper-api.alpaca.markets"
API_SECRET = "YOUR SECRET KEY"
BASE_URL = "https://paper-api.alpaca.markets/v2"

ALPACA_CREDS = {
"API_KEY":API_KEY,
Expand All @@ -18,18 +18,29 @@
}

class MLTrader(Strategy):
def initialize(self, symbol:str="SPY", cash_at_risk:float=.5):
def initialize(self, symbol:str="ASML", cash_at_risk:float=.5):
self.symbol = symbol
self.sleeptime = "24H"
self.last_trade = None
self.cash_at_risk = cash_at_risk
self.api = REST(base_url=BASE_URL, key_id=API_KEY, secret_key=API_SECRET)

def position_sizing(self):
cash = self.get_cash()
def position_sizing(self):
cash = self.get_cash()
last_price = self.get_last_price(self.symbol)
quantity = round(cash * self.cash_at_risk / last_price,0)
return cash, last_price, quantity
atr = self.calculate_atr(self.symbol)
take_profit, stop_loss = self.set_take_profit_stop_loss(last_price, atr)
quantity = round(cash * self.cash_at_risk / last_price, 0)
return cash, last_price, quantity, take_profit, stop_loss

def calculate_atr(self, symbol, period=14):
# Fetch historical data for ATR calculation, implement accordingly
pass

def set_take_profit_stop_loss(self, last_price, atr, multiplier=2):
take_profit = last_price + atr * multiplier
stop_loss = last_price - atr * multiplier
return take_profit, stop_loss

def get_dates(self):
today = self.get_datetime()
Expand All @@ -41,53 +52,54 @@ def get_sentiment(self):
news = self.api.get_news(symbol=self.symbol,
start=three_days_prior,
end=today)
news = [ev.__dict__["_raw"]["headline"] for ev in news]
news = [ai.__dict__["_raw"]["headline"] for ai in news]
probability, sentiment = estimate_sentiment(news)
return probability, sentiment

def on_trading_iteration(self):
cash, last_price, quantity = self.position_sizing()
cash, last_price, quantity, take_profit, stop_loss = self.position_sizing()
probability, sentiment = self.get_sentiment()

if cash > last_price:
if sentiment == "positive" and probability > .999:
if self.last_trade == "sell":
self.sell_all()

if cash > last_price:
if sentiment == "positive" and probability > .999:
if self.last_trade == "sell":
self.sell_all()
order = self.create_order(
self.symbol,
quantity,
"buy",
type="bracket",
take_profit_price=last_price*1.20,
stop_loss_price=last_price*.95
self.symbol,
quantity,
"buy",
type="bracket",
take_profit_price=take_profit,
stop_loss_price=stop_loss
)
self.submit_order(order)
self.submit_order(order)
self.last_trade = "buy"
elif sentiment == "negative" and probability > .999:
if self.last_trade == "buy":
self.sell_all()
elif sentiment == "negative" and probability > .999:
if self.last_trade == "buy":
self.sell_all()
order = self.create_order(
self.symbol,
quantity,
"sell",
type="bracket",
take_profit_price=last_price*.8,
stop_loss_price=last_price*1.05
self.symbol,
quantity,
"sell",
type="bracket",
take_profit_price=take_profit,
stop_loss_price=stop_loss
)
self.submit_order(order)
self.submit_order(order)
self.last_trade = "sell"

start_date = datetime(2020,1,1)
end_date = datetime(2023,12,31)
broker = Alpaca(ALPACA_CREDS)
strategy = MLTrader(name='mlstrat', broker=broker,
parameters={"symbol":"SPY",
parameters={"symbol":"ASML",
"cash_at_risk":.5})
strategy.backtest(
YahooDataBacktesting,
start_date,
end_date,
parameters={"symbol":"SPY", "cash_at_risk":.5}
parameters={"symbol":"ASML", "cash_at_risk":.5}
)
# trader = Trader()
# trader.add_strategy(strategy)
Expand Down