Skip to content

Commit

Permalink
Merge pull request #236 from tfukaza/better-modularity
Browse files Browse the repository at this point in the history
  • Loading branch information
tfukaza authored Dec 8, 2021
2 parents d8817e5 + 50d6906 commit b2438e4
Show file tree
Hide file tree
Showing 15 changed files with 322 additions and 217 deletions.
52 changes: 25 additions & 27 deletions examples/em_alpaca.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,72 +13,70 @@
import pandas as pd
import mplfinance as mpf


class EMAlgo(BaseAlgo):
def setup(self):
now = dt.datetime.now()
logging.info(f'EMAlgo.setup ran at: {now}')
logging.info(f"EMAlgo.setup ran at: {now}")

def init_ticker(ticker):
return {
ticker: {
'initial_price': None,
'ohlc': pd.DataFrame()
}
}
return {ticker: {"initial_price": None, "ohlc": pd.DataFrame()}}

self.tickers = {}
self.tickers.update(init_ticker('AAPL'))
self.tickers.update(init_ticker('MSFT'))
self.tickers.update(init_ticker("AAPL"))
self.tickers.update(init_ticker("MSFT"))

def main(self):
now = dt.datetime.now()
logging.info(f'EMAlgo.main ran at: {now}')
logging.info(f"EMAlgo.main ran at: {now}")

if now - now.replace(hour=0, minute=0, second=0, microsecond=0) <= dt.timedelta(seconds=60):
logger.info(f'It\'s a new day! Clearning OHLC caches!')
if now - now.replace(hour=0, minute=0, second=0, microsecond=0) <= dt.timedelta(
seconds=60
):
logger.info(f"It's a new day! Clearning OHLC caches!")
for ticker_value in self.tickers.values():
ticker_value['ohlc'] = pd.DataFrame()
ticker_value["ohlc"] = pd.DataFrame()

for ticker, ticker_value in self.tickers.items():
current_price = self.get_asset_price(ticker)
current_ohlc = self.get_asset_candle_list(ticker)
if ticker_value['initial_price'] is None:
ticker_value['initial_price'] = current_price
if ticker_value["initial_price"] is None:
ticker_value["initial_price"] = current_price

self.process_ticker(ticker, ticker_value, current_price, current_ohlc)

def process_ticker(self, ticker, ticker_data, current_price, current_ohlc):
initial_price = ticker_data['initial_price']
ohlc = ticker_data['ohlc']
initial_price = ticker_data["initial_price"]
ohlc = ticker_data["ohlc"]

# Calculate the price change
delta_price = current_price - initial_price

# Print stock info
logging.info(f'{ticker} current price: ${current_price}')
logging.info(f'{ticker} price change: ${delta_price}')
logging.info(f"{ticker} current price: ${current_price}")
logging.info(f"{ticker} price change: ${delta_price}")

# Update the OHLC data
print("ohlc", ohlc)
# Update the OHLC graph
mpf.plot(ohlc)


if __name__ == '__main__':
if __name__ == "__main__":
# Store the OHLC data in a folder called `em_storage` with each file stored as a csv document
csv_storage = CSVStorage(save_dir='em_storage')
csv_storage = CSVStorage(save_dir="em_storage")
# Our streamer and broker will be Alpaca. My secret keys are stored in `alpaca_secret.yaml`
alpaca = Alpaca(path='accounts/alpaca-secret.yaml', is_basic_account=True, paper_trader=True)
alpaca = Alpaca(
path="accounts/alpaca-secret.yaml", is_basic_account=True, paper_trader=True
)
em_algo = EMAlgo()
trader = LiveTrader(streamer=alpaca, broker=alpaca, storage=csv_storage, debug=True)

# Watch for Apple and Microsoft
trader.set_symbol('AAPL')
trader.set_symbol('MSFT')
trader.set_symbol("AAPL")
trader.set_symbol("MSFT")

trader.set_algo(em_algo)

# Update every minute
trader.start('1MIN', all_history=False)


trader.start("1MIN", all_history=False)
25 changes: 13 additions & 12 deletions examples/em_kraken.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,14 @@ def init_ticker(ticker):
fig = mpf.figure()
ax1 = fig.add_subplot(2, 1, 1)
ax2 = fig.add_subplot(3, 1, 3)

return {
ticker: {
"initial_price": None, "ohlc": pd.DataFrame(),
"fig": fig,
"ax1": ax1,
"ax2": ax2
"initial_price": None,
"ohlc": pd.DataFrame(),
"fig": fig,
"ax1": ax1,
"ax2": ax2,
}
}

Expand All @@ -56,7 +57,9 @@ def main(self):
ticker_value["initial_price"] = current_price

if current_ohlc.empty:
logging.warn(f"{ticker}'s get_asset_candle_list returned an empty list.")
logging.warn(
f"{ticker}'s get_asset_candle_list returned an empty list."
)
return

ticker_value["ohlc"] = ticker_value["ohlc"].append(current_ohlc)
Expand All @@ -75,19 +78,17 @@ def process_ticker(self, ticker, ticker_data, current_price):
logging.info(f"{ticker} price change: ${delta_price}")

# Update the OHLC graph
ticker_data['ax1'].clear()
ticker_data['ax2'].clear()
mpf.plot(ohlc, ax=ticker_data['ax1'], volume=ticker_data['ax2'], type="candle")
ticker_data["ax1"].clear()
ticker_data["ax2"].clear()
mpf.plot(ohlc, ax=ticker_data["ax1"], volume=ticker_data["ax2"], type="candle")
plt.pause(3)


if __name__ == "__main__":
# Store the OHLC data in a folder called `em_storage` with each file stored as a csv document
csv_storage = CSVStorage(save_dir="em_storage")
# Our streamer and broker will be Alpaca. My secret keys are stored in `alpaca_secret.yaml`
kraken = Kraken(
path="accounts/kraken-secret.yaml"
)
kraken = Kraken(path="accounts/kraken-secret.yaml")
em_algo = EMAlgo()
trader = LiveTrader(streamer=kraken, broker=kraken, storage=csv_storage, debug=True)

Expand Down
62 changes: 33 additions & 29 deletions examples/em_polygon.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,57 +15,60 @@
import matplotlib.pyplot as plt
import mplfinance as mpf


class EMAlgo(BaseAlgo):
def config(self):
self.watchlist = ["@BTC"]
self.interval = "1MIN"

def setup(self):
now = dt.datetime.now()
logging.info(f'EMAlgo.setup ran at: {now}')
logging.info(f"EMAlgo.setup ran at: {now}")

def init_ticker(ticker):
return {
ticker: {
'initial_price': None,
'ohlc': pd.DataFrame()
}
}
return {ticker: {"initial_price": None, "ohlc": pd.DataFrame()}}

self.tickers = {}
for ticker in self.watchlist:
self.tickers.update(init_ticker(ticker))

def main(self):
now = dt.datetime.now()
logging.info('*' * 20)
logging.info(f'EMAlgo.main ran at: {now}')
logging.info("*" * 20)
logging.info(f"EMAlgo.main ran at: {now}")

if now - now.replace(hour=0, minute=0, second=0, microsecond=0) <= dt.timedelta(seconds=60):
logger.info(f'It\'s a new day! Clearning OHLC caches!')
if now - now.replace(hour=0, minute=0, second=0, microsecond=0) <= dt.timedelta(
seconds=60
):
logger.info(f"It's a new day! Clearning OHLC caches!")
for ticker_value in self.tickers.values():
ticker_value['ohlc'] = pd.DataFrame(columns=['open', 'high', 'low', 'close', 'volume'], index=['timestamp'])
ticker_value["ohlc"] = pd.DataFrame(
columns=["open", "high", "low", "close", "volume"],
index=["timestamp"],
)

for ticker, ticker_value in self.tickers.items():
current_price = self.get_asset_price(ticker)
current_ohlc = self.get_asset_candle(ticker)
if current_ohlc is None:
logging.warn("No ohlc returned!")
return
ticker_value['ohlc'] = ticker_value['ohlc'].append(current_ohlc)
ticker_value['ohlc'] = ticker_value['ohlc'][~ticker_value['ohlc'].index.duplicated(keep='first')]
ticker_value["ohlc"] = ticker_value["ohlc"].append(current_ohlc)
ticker_value["ohlc"] = ticker_value["ohlc"][
~ticker_value["ohlc"].index.duplicated(keep="first")
]

if ticker_value['initial_price'] is None:
ticker_value['initial_price'] = current_price
if ticker_value["initial_price"] is None:
ticker_value["initial_price"] = current_price

logging.info('-' * 5 + ticker + '-' * 5)
logging.info("-" * 5 + ticker + "-" * 5)
self.process_ticker(ticker, ticker_value, current_price)
logging.info('-' * 20)
logging.info('*' * 20)
logging.info("-" * 20)
logging.info("*" * 20)

def process_ticker(self, ticker, ticker_data, current_price):
initial_price = ticker_data['initial_price']
ohlc = ticker_data['ohlc']
initial_price = ticker_data["initial_price"]
ohlc = ticker_data["ohlc"]

if ohlc.empty:
logging.warning(f"{ticker} does not have ohlc info! Not processing.")
Expand All @@ -75,18 +78,21 @@ def process_ticker(self, ticker, ticker_data, current_price):
delta_price = current_price - initial_price

# Print stock info
logging.info(f'{ticker} current price: ${current_price}')
logging.info(f'{ticker} price change: ${delta_price}')
logging.info(f"{ticker} current price: ${current_price}")
logging.info(f"{ticker} price change: ${delta_price}")

axes.clear()
mpf.plot(ohlc, ax=axes, block=False)
plt.pause(3)

if __name__ == '__main__':

if __name__ == "__main__":
# Store the OHLC data in a folder called `em_storage` with each file stored as a csv document
csv_storage = CSVStorage(save_dir='em-polygon-storage')
csv_storage = CSVStorage(save_dir="em-polygon-storage")
# Our streamer will be Polygon and the broker will be Harvest's paper trader. My secret keys are stored in `polygon-secret.yaml`
polygon = PolygonStreamer(path='accounts/polygon-secret.yaml', is_basic_account=True)
polygon = PolygonStreamer(
path="accounts/polygon-secret.yaml", is_basic_account=True
)
paper = PaperBroker()
em_algo = EMAlgo()
trader = LiveTrader(streamer=polygon, broker=paper, storage=csv_storage, debug=True)
Expand All @@ -96,6 +102,4 @@ def process_ticker(self, ticker, ticker_data, current_price):
fig = mpf.figure()
axes = fig.add_subplot(1, 1, 1)
# Update every minute
trader.start('1MIN', all_history=False)


trader.start("1MIN", all_history=False)
19 changes: 10 additions & 9 deletions harvest/algo.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,9 @@ def __init__(self):
self.aggregations = None
self.watchlist = []

def init(self, stats):
self.stats = stats

def config(self):
"""
This method is called before any other methods (except for __init__),
Expand Down Expand Up @@ -248,8 +251,8 @@ def filter_option_chain(
"""
if symbol is None:
symbol = self.watchlist[0]
lower_exp = convert_input_to_datetime(lower_exp, self.trader.timezone)
upper_exp = convert_input_to_datetime(upper_exp, self.trader.timezone)
lower_exp = convert_input_to_datetime(lower_exp, self.stats.timezone)
upper_exp = convert_input_to_datetime(upper_exp, self.stats.timezone)

exp_dates = self.get_option_chain_info(symbol)["exp_dates"]
if lower_exp is not None:
Expand Down Expand Up @@ -303,7 +306,7 @@ def get_option_chain(self, symbol: str, date):
"""
if symbol is None:
symbol = self.watchlist[0]
date = convert_input_to_datetime(date, self.trader.timezone)
date = convert_input_to_datetime(date, self.stats.timezone)
print(f"Date: {date}\n")
return self.trader.fetch_chain_data(symbol, date)

Expand Down Expand Up @@ -336,7 +339,7 @@ def _default_param(self, symbol, interval, ref, prices):
raise Exception(f"No prices found for symbol {symbol}")
else:
if interval is None:
interval = self.trader.interval[symbol]["interval"]
interval = self.trader.stats.interval[symbol]["interval"]
else:
interval = interval_string_to_enum(interval)
if prices == None:
Expand Down Expand Up @@ -610,7 +613,7 @@ def get_asset_candle(self, symbol: str, interval=None) -> pd.DataFrame():
if len(symbol) <= 6:
df = self.trader.storage.load(symbol, interval).iloc[[-1]][symbol]
print(self.trader.storage.load(symbol, interval))
return pandas_timestamp_to_local(df, self.trader.timezone)
return pandas_timestamp_to_local(df, self.stats.timezone)
debugger.warning("Candles not available for options")
return None

Expand Down Expand Up @@ -639,7 +642,7 @@ def get_asset_candle_list(
if interval is None:
interval = self.interval
df = self.trader.storage.load(symbol, interval)[symbol]
return pandas_timestamp_to_local(df, self.trader.timezone)
return pandas_timestamp_to_local(df, self.stats.timezone)

def get_asset_returns(self, symbol=None) -> float:
"""Returns the return of a specified asset.
Expand Down Expand Up @@ -770,9 +773,7 @@ def get_datetime(self):
:returns: The current date and time as a datetime object
"""
return datetime_utc_to_local(
self.trader.streamer.timestamp, self.trader.timezone
)
return datetime_utc_to_local(self.stats.timestamp, self.stats.timezone)

def get_option_position_quantity(self, symbol: str = None) -> bool:
"""Returns the number of types of options held for a stock.
Expand Down
Loading

0 comments on commit b2438e4

Please sign in to comment.