def __init__(self, manager, name, symbols, properties, required=[], mainBarsize=""): self.logger = MyLogger.getLogger(name, file=f"{name}.log", level=logging.INFO) self.clock = TradingClock.getInstance() self.manager: Manager = manager self.name = name self.id = uuid.uuid1() self.clock = TradingClock.getInstance() self.symbols = symbols self.mainBarsize = mainBarsize # Check properties self.__dict__ = {**self.__dict__, **properties} assert \ all([rp in self.__dict__.keys() and self.__dict__[rp] is not None for rp in required]), \ f"Missing required properties {[rp for rp in required if (rp not in self.__dict__.keys()) or (self.__dict__[rp] is None)]}" self.__symbols = {} # map symbol to datas self.__requests = {} # map requests to symbol self.indicators = {} # Call abstract setup method self.setup()
def __init__(self, parent, simtracker, account, *args, **kwargs): tk.Frame.__init__(self, parent, *args, **kwargs) self.logger = MyLogger.getLogger('StratView') self.simtracker = simtracker self.account = account self.canvas = None self.legend = tk.Frame(self) self.legend.pack(side=tk.RIGHT)
def __init__(self, endpoint): self.logger = MyLogger.getLogger('TestApp', file='trades.log', level=MyLogger.TRADE) self.clock = TradingClock.getInstance() self.datafactory = DataFactory.getInstance() self.endpoint = endpoint self.clock.add_callback(self.time_change) self.pending_orders = {} self.historical_subscribers = {}
def __init__(self, startingcapital): self.logger = MyLogger.getLogger("ACC") self.datafactory = DataFactory.getInstance() self.clock = TradingClock.getInstance() self.clock.add_callback(self.time_change) self.orderLedger = {} self.portfolio = {} # Portfolio(startingcapital) self.cash = startingcapital self.CASH = pd.Series() self.HOLDINGS = pd.Series() self.done = False
def __init__(self, simtracker, account, strategies, rapid=False, times=None, setup_days=3, barsize="5 min"): threading.Thread.__init__(self) self.simtracker = simtracker self.account = account self.logger = MyLogger.getLogger('main') self.strategies = strategies self.symbols = functools.reduce(lambda a, b: set(a + b), [skwa["symbols"] for s, skwa in strategies]) self.barsize = barsize self.rapid = rapid self.setup_days = setup_days if times is None: self.times = [ datetime.time(10, 30), datetime.time(11, 30), datetime.time(12, 30), datetime.time(13, 30), datetime.time(14, 30), datetime.time(15, 30), ] else: self.times = times
def replace_empties(data, goal=None): logger = MyLogger.getLogger("RepUtil") if goal is not None and goal < data.index[-1]: logger.warn(f"Goal date {goal} is pre-data end {data.index[-1]}, resetting") goal = data.index[-1] dates = sorted(list(set(pd.Series(data.index).transform(lambda x: x.date())))) date = dates[0] end_date = dates[-1] if goal is None else goal.date() period = min([abs(d1 - d2) for d1, d2 in zip(data.index[1:], data.index[:-1])]) while date <= end_date: if tcal.is_partial_trading_day(date) or tcal.is_trading_day(date): #TODO: Bug - min period changed if get a partial bar if period > datetime.timedelta(minutes=5): # TODO: Bit ugly.... shoed in missing_ranges = [] if date not in dates: missing_ranges = [[data.index[0].replace(year=date.year, month=date.month, day=date.day)]] else: ttimes = tcal.tradingtimes(date) if goal is None: missing_times = ttimes[~ttimes.isin(data.index)] else: missing_times = ttimes[~ttimes.isin(data.index) & (ttimes <= goal)] missing_ranges = [] if len(missing_times): # Blocks of missing data missing_ranges.append([missing_times[0]]) for missing_time in missing_times[1:]: previous = missing_ranges[-1][-1] next_span = missing_time - previous if next_span != period: missing_ranges.append([missing_time]) else: missing_ranges[-1].append(missing_time) # chuck repeated in there for missing_range in missing_ranges: try: before = data[data.index < missing_range[0]] after = data[data.index > missing_range[-1]] previous = before.iloc[-1] patch = pd.DataFrame({"Open": previous.Close, "High": previous.Close, "Low": previous.Close, "Close": previous.Close, "Adj Close": previous.Close, "Volume": 0}, index=missing_range) data = pd.concat([before, patch, after]) data = data[~data.index.duplicated(keep='last')] except Exception as e: print(f"Repair failed for {e}") date += datetime.timedelta(days=1) return data
def __init__(self): if DataFactory.__instance != None: raise Exception("Singleton") else: self.logger = MyLogger.getLogger("DataFac") DataFactory.__instance = self
def __init__(self, parent, simtracker, account, *args, **kwargs): tk.Frame.__init__(self, parent, *args, **kwargs) self.simtracker = simtracker self.account = account self.logger = MyLogger.getLogger("PView") tk.Button(self, text="Refresh", command=self.refresh, relief=tk.GROOVE, borderwidth=1) \ .pack(side=tk.BOTTOM, expand=True, fill=tk.X) tk.Label(self, text="Orders").pack() self.orders_entry = tk.Entry(self) self.orders_entry.pack() self.orders_entry.bind('<Return>', self.refresh) self.orderstv_frame = tk.Frame(self) self.orderstv = ttk.Treeview(self.orderstv_frame) self.orderstv["columns"] = [ "id", "Symbol", "Action", "Time", "Price", "Filled" ] self.orderstv["show"] = "headings" self.orderstv.heading("id", text="") self.orderstv.heading("Symbol", text="Symb") self.orderstv.heading("Action", text="Action") self.orderstv.heading("Time", text="Time") self.orderstv.heading("Price", text="Price") self.orderstv.heading("Filled", text="Filled") col_width = self.orderstv.winfo_width() // len( self.orderstv['columns']) for col in self.orderstv['columns']: self.orderstv.heading(col, anchor=tk.CENTER) self.orderstv.column(col, anchor=tk.CENTER, width=col_width) # set column width self.orderstv.pack(fill=tk.BOTH, expand=True) self.orderstv_frame.pack(fill=tk.BOTH, expand=True) # treeScroll = ttk.Scrollbar(self.orderstv) # treeScroll.configure(command=self.orderstv.yview) # self.orderstv.configure(yscrollcommand=treeScroll.set) tk.Label(self, text="Portfolio").pack() self.holdingstv_frame = tk.Frame(self) self.holdingstv = ttk.Treeview(self.holdingstv_frame) self.holdingstv["columns"] = [ "Symbol", "Vol", "Avg Price", "Price", "Change", "Realised" ] self.holdingstv["show"] = "headings" self.holdingstv.heading("Symbol", text="Symb") self.holdingstv.heading("Vol", text="Vol") self.holdingstv.heading("Avg Price", text="Avg Price") self.holdingstv.heading("Price", text="Price") self.holdingstv.heading("Change", text="%") self.holdingstv.heading("Realised", text="Realised") col_width = self.holdingstv.winfo_width() // len( self.holdingstv['columns']) for col in self.holdingstv['columns']: self.holdingstv.heading(col, anchor=tk.CENTER) self.holdingstv.column(col, anchor=tk.CENTER, width=col_width) # set column width self.holdingstv.pack(fill=tk.BOTH, expand=True) self.holdingstv_frame.pack(fill=tk.BOTH, expand=True) # ttk.Separator(self, orient=tk.HORIZONTAL).pack(fill=tk.X, expand=1) tk.Label(self, text="Value").pack() self.plot_frame = tk.Frame(self, relief=tk.GROOVE, borderwidth=1) self.f = Figure(figsize=(5, 5), dpi=100) self.a = self.f.add_subplot(111) self.a.grid(True) self.a.xaxis.set_major_formatter(mdates.DateFormatter("%m-%d")) self.a.xaxis.set_minor_formatter(mdates.DateFormatter("%m-%d")) self.a.plot([TradingClock.getInstance().sync_datetime], [self.account.value]) # self.cash, = self.a.plot([TradingClock.getInstance().sync_datetime], [self.account.cash]) # self.holdings, = self.a.plot([TradingClock.getInstance().sync_datetime], [self.account.holdings]) self.canvas = FigureCanvasTkAgg(self.f, self.plot_frame) self.canvas.get_tk_widget().pack(side=tk.BOTTOM, fill=tk.BOTH, expand=True) self.plot_frame.pack(fill=tk.BOTH, expand=True)
def snapshot_to_fig(snapshot, account=None, savefile=None): logger = MyLogger.getLogger('SS2Fig') legend_indicators = {} data = snapshot.data def getcolor(ii): colors = ["blue", "green", "red", "cyan", "magenta", "yellow"] return colors[ii % len(colors)] def get_addplot(ii, key, indicator, iargs): if "color" not in iargs: iargs["color"] = getcolor(ii) legend_indicators[key] = iargs["color"] if len(indicator) < len(data): missing_points = len(data) - len(indicator) indicator = pd.concat( [indicator, pd.Series([np.nan] * missing_points)]) logger.warn( f"Missing {missing_points} data points for indicator {key}" ) return fplt.make_addplot(indicator, **iargs) indicator_adps = [ get_addplot(i, key, indicator, iargs) for i, (key, (indicator, iargs)) in enumerate(snapshot.indicators.items()) ] trade_adps = [] symbol = snapshot.contract.symbol period = min( [abs(d1 - d2) for d1, d2 in zip(data.index[1:], data.index[:-1])]) if account is not None: # GET THE BUYS try: buy_times, buy_prices = map( list, zip(*[(order["time"], order["lastFillPrice"]) for id, order in account.orderLedger.items() if order["contract"].symbol == symbol and data.index[0] <= order["time"] <= data.index[-1] and order["order"].action == "BUY"])) if len(buy_times): if period > datetime.timedelta(minutes=5): buy_times = [bt.date() for bt in buy_times] buys = pd.Series([ buy_prices[buy_times.index(t)] if t.date() in buy_times else np.nan for t in data.index ]) else: buys = pd.Series([ buy_prices[buy_times.index(t)] if t in buy_times else np.nan for t in data.index ]) if np.any(~np.isnan(buys)): trade_adps.append( fplt.make_addplot( buys.transform(lambda x: x * 0.9975), scatter=True, marker=r'$\uparrow$', markersize=96, color="green")) except ValueError as e: pass except Exception as e: logger.warn(f"Failed buy markers: {e}") # GET THE SELLS try: sell_times, sell_prices = map( list, zip(*[(order["time"], order["lastFillPrice"]) for id, order in account.orderLedger.items() if order["contract"].symbol == symbol and data.index[0] <= order["time"] <= data.index[-1] and order["order"].action == "SELL"])) if len(sell_times): if period > datetime.timedelta(minutes=5): sell_times = [st.date() for st in sell_times] sells = pd.Series([ sell_prices[sell_times.index(t)] if t.date() in sell_times else np.nan for t in data.index ]) else: sells = pd.Series([ sell_prices[sell_times.index(t)] if t in sell_times else np.nan for t in data.index ]) if np.any(~np.isnan(sells)): trade_adps.append( fplt.make_addplot( sells.transform(lambda x: x * 1.0025), scatter=True, marker=r'$\downarrow$', markersize=96, color="red")) except ValueError as e: pass except Exception as e: logger.warn(f"Failed sell markers: {e}") mc = fplt.make_marketcolors(up='#7DFFB8', down='#FF7979', edge='black', wick='black', volume='in') s = fplt.make_mpf_style(base_mpl_style="seaborn", mavcolors=["lightseagreen", "orange"], facecolor="#F9FBFD", gridcolor="#F2F2F2", gridstyle="--", marketcolors=mc) dates = list(set(pd.Series(data.index).transform(lambda x: x.date()))) plotargs = { "type": 'candle', "style": s, "title": symbol, "ylabel": 'Price ($)', "volume": True, "addplot": indicator_adps + trade_adps, "returnfig": True } if savefile is not None: # if period == datetime.timedelta(days=1): # data.index = pd.DatetimeIndex(pd.Series(data.index).transform(lambda x:x.date()), dtype=datetime.date) plotargs["savefig"] = savefile if type(data.index) != pd.DatetimeIndex: # TODO: shouldn't come here data.index = pd.DatetimeIndex(pd.to_datetime(data.index, utc=True)) logger.warn("ERROR index not datetime") for addplots in [ indicator_adps + trade_adps, indicator_adps, trade_adps, [] ]: try: plotargs["addplot"] = addplots fig, ax = fplt.plot(data, **plotargs) break except: pass #fig, ax = fplt.plot(data, **plotargs) if period <= datetime.timedelta(minutes=5): loc = mticker.MultipleLocator(73) ax[0].xaxis.set_major_locator(loc) else: loc = mticker.MultipleLocator(1) #loc = mticker.MultipleLocator(max(len(data)//20, 1)) ax[0].xaxis.set_major_locator(loc) return fig, ax, legend_indicators
from Services.MyLogger import MyLogger from Services.SimTracker import SimTracker from Services.SimViewer import StrategyView from Services.TradingClock import TradingClock from Strategies.Crystal import CrystalV3 from Strategies.RocketCatcher import RocketCatcher from _config import TICKERS_LEDGER from _devconfig import * import random import pandas as pd if __name__ == "__main__": MyLogger.configure(20) logger = MyLogger.getLogger("MAIN") # services DataFactory.repaired = True DataFactory.live_data = True clock, datafactory = TradingClock.getInstance(), DataFactory.getInstance() # absolute times to check for an update times = [ datetime.time(9, 30), datetime.time(10, 30), datetime.time(11, 30), datetime.time(12, 30), datetime.time(13, 30), datetime.time(14, 30), datetime.time(15, 30),
from Components.Account import Account from Services.Datafactory import DataFactory from Components.Process import ThreadedTask import pandas as pd import random if __name__ == "__main__": # TODO: proper portfolio # TODO: data cleaning # TODO: parmas DataFactory.repaired = True logger = MyLogger.getLogger("Optimiser", file="optimiser.log", level=MyLogger.OPTY) def get_random_symbols(k=25): tickers_ledger = pd.read_csv(TICKERS_LEDGER) asx_listings = pd.read_csv(ASX_LISTING) return random.choices([ s for t, s, mc, l in zip(asx_listings.title.values, asx_listings.code.values, asx_listings.market_cap.values, asx_listings.low.values) if (0.01 < l < 5) and (s + ".AX" in tickers_ledger.TICKER.values) and (t.find("Ltd") > 0) ], k=k) strat = 1
import os import pandas as pd from DataScrape.ScrapeReddit import ASX_LISTING from Datasets.scrape_data import replace_empties from Services.Datafactory import DataFactory from Services.MyLogger import MyLogger from _config import TICKERS_LEDGER, ASX_GAME if __name__ == "__main__": logger = MyLogger.getLogger("repair util", level=20) datafactory = DataFactory.getInstance() asx_game = pd.read_csv(ASX_GAME) to_replace = [s + ".AX" for s in asx_game.Code] print(f"TO REPLACE ({len(to_replace)}):") for i, ticker in enumerate(to_replace): DFS = DataFactory.repaired try: print(f"{ticker} ({i + 1}/{len(to_replace)})") datafactory.repaired = False data = datafactory.loadSymbol(ticker).dropna() repaired_data = replace_empties(data) datafactory.repaired = True repaired_data.to_csv( datafactory.getDataDir("5 min") +