def __init__(self, *, training=True, fitting_file='ETH-USD_2018-12-31.xz', testing_file='ETH-USD_2019-01-01.xz', step_size=1, max_position=5, window_size=4, frame_stack=False): # properties required for instantiation PriceJump.instance_count += 1 self._seed = int(PriceJump.instance_count) # seed self._random_state = np.random.RandomState(seed=self._seed) self.training = training self.step_size = step_size self.fee = BROKER_FEE self.max_position = max_position self.window_size = window_size self.frame_stack = frame_stack self.frames_to_add = 3 if self.frame_stack else 0 self.action = 0 # derive gym.env properties self.actions = np.eye(3) self.sym = testing_file[:7] # slice the CCY from the filename # properties that get reset() self.reward = 0.0 self.done = False self.local_step_number = 0 self.midpoint = 0.0 self.observation = None # get Broker class to keep track of PnL and orders self.broker = Broker(max_position=max_position) # get historical data for simulations self.sim = Sim(use_arctic=False) fitting_data_filepath = '{}/data_exports/{}'.format( self.sim.cwd, fitting_file) data_used_in_environment = '{}/data_exports/{}'.format( self.sim.cwd, testing_file) # print('Fitting data: {}\nTesting Data: {}'.format(fitting_data_filepath, # data_used_in_environment)) fitting_data = self.sim.import_csv(filename=fitting_data_filepath) fitting_data['coinbase_midpoint'] = np.log( fitting_data['coinbase_midpoint'].values) fitting_data['coinbase_midpoint'] = fitting_data['coinbase_midpoint']. \ pct_change().fillna(method='bfill') self.sim.fit_scaler(fitting_data) del fitting_data self.data = self.sim.import_csv(filename=data_used_in_environment) self.prices_ = self.data[ 'coinbase_midpoint'].values # used to calculate PnL self.normalized_data = self.data.copy() self.data = self.data.values self.normalized_data['coinbase_midpoint'] = np.log( self.normalized_data['coinbase_midpoint'].values) self.normalized_data['coinbase_midpoint'] = ( self.normalized_data['coinbase_midpoint'] - self.normalized_data['coinbase_midpoint'].shift(1)).fillna( method='bfill') self.tns = TnS() self.rsi = RSI() logger.info("Pre-scaling {}-{} data...".format(self.sym, self._seed)) self.normalized_data = self.normalized_data.apply(self.sim.z_score, axis=1).values logger.info("...{}-{} pre-scaling complete.".format( self.sym, self._seed)) # rendering class self._render = TradingGraph(sym=self.sym) # graph midpoint prices self._render.reset_render_data( y_vec=self.prices_[:np.shape(self._render.x_vec)[0]]) self.data_buffer, self.frame_stacker = list(), list() self.action_space = spaces.Discrete(len(self.actions)) variable_features_count = len(self.inventory_features) + len(self.actions) + 1 + \ len(PriceJump.indicator_features) if self.frame_stack: shape = (4, len(PriceJump.features) + variable_features_count, self.window_size) else: shape = (self.window_size, len(PriceJump.features) + variable_features_count) self.observation_space = spaces.Box(low=self.data.min(), high=self.data.max(), shape=shape, dtype=np.int) print('PriceJump #{} instantiated.\nself.observation_space.shape : {}'. format(PriceJump.instance_count, self.observation_space.shape))
def __init__(self, *, fitting_file='ETH-USD_2018-12-31.xz', testing_file='ETH-USD_2019-01-01.xz', step_size=1, max_position=5, window_size=10, seed=1, action_repeats=10, training=True, format_3d=False, z_score=True): # properties required for instantiation self.action_repeats = action_repeats self._seed = seed self._random_state = np.random.RandomState(seed=self._seed) self.training = training self.step_size = step_size self.max_position = max_position self.window_size = window_size self.format_3d = format_3d # e.g., [window, features, *NEW_AXIS*] self.action = 0 # derive gym.env properties self.actions = np.eye(3) self.sym = testing_file[:7] # slice the CCY from the filename # properties that get reset() self.reward = 0.0 self.done = False self.local_step_number = 0 self.midpoint = 0.0 self.observation = None # get Broker class to keep track of PnL and orders self.broker = Broker(max_position=max_position) # get historical data for simulations self.sim = Sim(use_arctic=False) self.data = self._load_environment_data(fitting_file, testing_file) self.prices_ = self.data[ 'coinbase_midpoint'].values # used to calculate PnL self.normalized_data = self.data.copy() self.data = self.data.values self.max_steps = self.data.shape[0] - self.step_size * \ self.action_repeats - 1 # normalize midpoint data self.normalized_data['coinbase_midpoint'] = \ np.log(self.normalized_data['coinbase_midpoint'].values) self.normalized_data['coinbase_midpoint'] = ( self.normalized_data['coinbase_midpoint'] - self.normalized_data['coinbase_midpoint'].shift(1)).fillna(0.) # load indicators into the indicator manager self.tns = IndicatorManager() self.rsi = IndicatorManager() for window in INDICATOR_WINDOW: self.tns.add(('tns_{}'.format(window), TnS(window=window))) self.rsi.add(('rsi_{}'.format(window), RSI(window=window))) if z_score: logger.info("Pre-scaling {}-{} data...".format( self.sym, self._seed)) self.normalized_data = self.normalized_data.apply(self.sim.z_score, axis=1).values logger.info("...{}-{} pre-scaling complete.".format( self.sym, self._seed)) else: self.normalized_data = self.normalized_data.values # rendering class self._render = TradingGraph(sym=self.sym) # graph midpoint prices self._render.reset_render_data( y_vec=self.prices_[:np.shape(self._render.x_vec)[0]]) # buffer for appending lags self.data_buffer = list() self.action_space = spaces.Discrete(len(self.actions)) self.reset() # reset to load observation.shape self.observation_space = spaces.Box(low=-10, high=10, shape=self.observation.shape, dtype=np.float32) print( '{} PriceJump #{} instantiated.\nself.observation_space.shape : {}' .format(self.sym, self._seed, self.observation_space.shape))
def __init__(self, fitting_file='BTC-USD_2019-04-07.csv.xz', testing_file='BTC-USD_2019-04-08.csv.xz', step_size=1, max_position=5, window_size=10, seed=1, action_repeats=10, training=True, format_3d=True, z_score=True, reward_type='default', scale_rewards=True, ema_alpha=EMA_ALPHA): """ Base class for creating environments extending OpenAI's GYM framework. :param fitting_file: historical data used to fit environment data (i.e., previous trading day) :param testing_file: historical data used in environment :param step_size: increment size for steps (NOTE: leave a 1, otherwise market transaction data will be overlooked) :param max_position: maximum number of positions able to hold in inventory :param window_size: number of lags to include in observation space :param seed: random seed number :param action_repeats: number of steps to take in environment after a given action :param training: if TRUE, then randomize starting point in environment :param format_3d: if TRUE, reshape observation space from matrix to tensor :param z_score: if TRUE, normalize data set with Z-Score, otherwise use Min-Max (i.e., range of 0 to 1) :param reward_type: method for calculating the environment's reward: 1) 'trade_completion' --> reward is generated per trade's round trip 2) 'continuous_total_pnl' --> change in realized & unrealized pnl between time steps 3) 'continuous_realized_pnl' --> change in realized pnl between time steps 4) 'continuous_unrealized_pnl' --> change in unrealized pnl between time steps 5) 'normed' --> refer to https://arxiv.org/abs/1804.04216v1 6) 'div' --> reward is generated per trade's round trip divided by inventory count (again, refer to https://arxiv.org/abs/1804.04216v1) 7) 'asymmetrical' --> extended version of *default* and enhanced with a reward for being filled above/below midpoint, and returns only negative rewards for Unrealized PnL to discourage long-term speculation. 8) 'asymmetrical_adj' --> extended version of *default* and enhanced with a reward for being filled above/below midpoint, and weighted up/down unrealized returns. 9) 'default' --> Pct change in Unrealized PnL + Realized PnL of respective time step. :param ema_alpha: decay factor for EMA, usually between 0.9 and 0.9999; if NONE, raw values are returned in place of smoothed values """ # properties required for instantiation self.action_repeats = action_repeats self._seed = seed self._random_state = np.random.RandomState(seed=self._seed) self.training = training self.step_size = step_size self.max_position = max_position self.window_size = window_size self.reward_type = reward_type self.format_3d = format_3d # e.g., [window, features, *NEW_AXIS*] self.sym = testing_file[:7] # slice the CCY from the filename self.scale_rewards = scale_rewards # properties that get reset() self.reward = 0.0 self.done = False self.local_step_number = 0 self.midpoint = 0.0 self.observation = None self.action = 0 self.last_pnl = 0. self.last_midpoint = None self.midpoint_change = None # properties to override in sub-classes self.actions = None self.broker = None self.action_space = None self.observation_space = None # get historical data for simulations self.sim = Sim(z_score=z_score, alpha=ema_alpha) self.prices_, self.data, self.normalized_data = self.sim.load_environment_data( fitting_file=fitting_file, testing_file=testing_file, include_imbalances=True, as_pandas=False) self.best_bid = self.best_ask = None self.max_steps = self.data.shape[ 0] - self.step_size * self.action_repeats - 1 # load indicators into the indicator manager self.tns = IndicatorManager() self.rsi = IndicatorManager() for window in INDICATOR_WINDOW: self.tns.add( ('tns_{}'.format(window), TnS(window=window, alpha=ema_alpha))) self.rsi.add( ('rsi_{}'.format(window), RSI(window=window, alpha=ema_alpha))) # conditionally load PnlNorm, since it calculates in O(n) time complexity self.pnl_norm = PnlNorm( window=INDICATOR_WINDOW[0], alpha=None) if self.reward_type == 'normed' else None # rendering class self._render = TradingGraph(sym=self.sym) # graph midpoint prices self._render.reset_render_data( y_vec=self.prices_[:np.shape(self._render.x_vec)[0]]) # buffer for appending lags self.data_buffer = list()
def __init__(self, training=True, fitting_file='ETH-USD_2018-12-31.xz', testing_file='ETH-USD_2019-01-01.xz', step_size=1, max_position=1, window_size=50, seed=1, frame_stack=False): # properties required for instantiation self._random_state = np.random.RandomState(seed=seed) self._seed = seed self.training = training self.step_size = step_size self.fee = BROKER_FEE self.max_position = max_position self.window_size = window_size self.frame_stack = frame_stack self.frames_to_add = 3 if self.frame_stack else 0 self.inventory_features = ['long_inventory', 'short_inventory', 'long_unrealized_pnl', 'short_unrealized_pnl'] self._action = 0 # derive gym.env properties self.actions = ((1, 0, 0), # 0. do nothing (0, 1, 0), # 1. buy (0, 0, 1) # 2. sell ) self.sym = testing_file[:7] # slice the CCY from the filename # properties that get reset() self.reward = 0.0 self.done = False self._local_step_number = 0 self.midpoint = 0.0 self.observation = None # get historical data for simulations self.broker = Broker(max_position=max_position) self.sim = Sim(use_arctic=False) # Turn to true if Bitifinex is in the dataset (e.g., include_bitfinex=True) self.features = self.sim.get_feature_labels(include_system_time=False, include_bitfinex=False) fitting_data_filepath = '{}/data_exports/{}'.format(self.sim.cwd, fitting_file) data_used_in_environment = '{}/data_exports/{}'.format(self.sim.cwd, testing_file) print('Fitting data: {}\nTesting Data: {}'.format(fitting_data_filepath, data_used_in_environment)) self.sim.fit_scaler(self.sim.import_csv(filename=fitting_data_filepath)) self.data = self.sim.import_csv(filename=data_used_in_environment) self.prices = self.data['coinbase_midpoint'].values self.data = self.data.apply(self.sim.z_score, axis=1) self.data = self.data.values self.data_buffer, self.frame_stacker = list(), list() self.action_space = spaces.Discrete(len(self.actions)) variable_features_count = len(self.inventory_features) + len(self.actions) + 1 if self.frame_stack is False: shape = (len(self.features) + variable_features_count, self.window_size) else: shape = (len(self.features) + variable_features_count, self.window_size, 4) self.observation_space = spaces.Box(low=self.data.min(), high=self.data.max(), shape=shape, dtype=np.int) self.reset()
def __init__(self, *, fitting_file='LTC-USD_2019-04-07.csv.xz', testing_file='LTC-USD_2019-04-08.csv.xz', step_size=1, max_position=5, window_size=10, seed=1, action_repeats=10, training=True, format_3d=False, z_score=True): # properties required for instantiation self.action_repeats = action_repeats self._seed = seed self._random_state = np.random.RandomState(seed=self._seed) self.training = training self.step_size = step_size self.max_position = max_position self.window_size = window_size self.format_3d = format_3d # e.g., [window, features, *NEW_AXIS*] self.action = 0 # derive gym.env properties self.actions = np.eye(3, dtype=np.float32) self.sym = testing_file[:7] # slice the CCY from the filename # properties that get reset() self.reward = 0.0 self.done = False self.local_step_number = 0 self.midpoint = 0.0 self.observation = None # get Broker class to keep track of PnL and orders self.broker = Broker(max_position=max_position) # get historical data for simulations self.sim = Sim(use_arctic=False, z_score=z_score) self.prices_, self.data, self.normalized_data = self.sim.load_environment_data( fitting_file, testing_file) self.max_steps = self.data.shape[0] - self.step_size * \ self.action_repeats - 1 # load indicators into the indicator manager self.tns = IndicatorManager() self.rsi = IndicatorManager() for window in INDICATOR_WINDOW: self.tns.add(('tns_{}'.format(window), TnS(window=window))) self.rsi.add(('rsi_{}'.format(window), RSI(window=window))) # rendering class self._render = TradingGraph(sym=self.sym) # graph midpoint prices self._render.reset_render_data( y_vec=self.prices_[:np.shape(self._render.x_vec)[0]]) # buffer for appending lags self.data_buffer = list() self.action_space = spaces.Discrete(len(self.actions)) self.reset() # reset to load observation.shape self.observation_space = spaces.Box(low=-10, high=10, shape=self.observation.shape, dtype=np.float32) print( '{} PriceJump #{} instantiated.\nself.observation_space.shape : {}' .format(self.sym, self._seed, self.observation_space.shape))
def __init__(self, fitting_file='LTC-USD_2019-04-07.csv.xz', testing_file='LTC-USD_2019-04-08.csv.xz', step_size=1, max_position=5, window_size=10, seed=1, action_repeats=10, training=True, format_3d=False, z_score=True, reward_type='trade_completion', scale_rewards=True): """ Base class for creating environments extending OpenAI's GYM framework. :param fitting_file: historical data used to fit environment data (i.e., previous trading day) :param testing_file: historical data used in environment :param step_size: increment size for steps (NOTE: leave a 1, otherwise market transaction data will be overlooked) :param max_position: maximum number of positions able to hold in inventory :param window_size: number of lags to include in observation space :param seed: random seed number :param action_repeats: number of steps to take in environment after a given action :param training: if TRUE, then randomize starting point in environment :param format_3d: if TRUE, reshape observation space from matrix to tensor :param z_score: if TRUE, normalize data set with Z-Score, otherwise use Min-Max (i.e., range of 0 to 1) :param reward_type: method for calculating the environment's reward: 1) 'trade_completion' --> reward is generated per trade's round trip 2) 'continuous_total_pnl' --> change in realized & unrealized pnl between time steps 3) 'continuous_realized_pnl' --> change in realized pnl between time steps 4) 'continuous_unrealized_pnl' --> change in unrealized pnl between time steps """ # properties required for instantiation self.action_repeats = action_repeats self._seed = seed self._random_state = np.random.RandomState(seed=self._seed) self.training = training self.step_size = step_size self.max_position = max_position self.window_size = window_size self.reward_type = reward_type self.format_3d = format_3d # e.g., [window, features, *NEW_AXIS*] self.sym = testing_file[:7] # slice the CCY from the filename self.scale_rewards = scale_rewards # properties that get reset() self.reward = 0.0 self.done = False self.local_step_number = 0 self.midpoint = 0.0 self.observation = None self.action = 0 self.last_pnl = 0. # properties to override in sub-classes self.actions = None self.broker = None self.action_space = None self.observation_space = None # get historical data for simulations self.sim = Sim(use_arctic=False, z_score=z_score) self.prices_, self.data, self.normalized_data = self.sim.load_environment_data( fitting_file, testing_file) self.best_bid = self.best_ask = None self.max_steps = self.data.shape[ 0] - self.step_size * self.action_repeats - 1 # load indicators into the indicator manager self.tns = IndicatorManager() self.rsi = IndicatorManager() for window in INDICATOR_WINDOW: self.tns.add(('tns_{}'.format(window), TnS(window=window))) self.rsi.add(('rsi_{}'.format(window), RSI(window=window))) # rendering class self._render = TradingGraph(sym=self.sym) # graph midpoint prices self._render.reset_render_data( y_vec=self.prices_[:np.shape(self._render.x_vec)[0]]) # buffer for appending lags self.data_buffer = list()