Exemplo n.º 1
0
def FindOldestDate(shc_market_data_lines, shc_market_line_index):
    last_date = None
    for shc in shc_market_data_lines.keys():
        contract = ci.ContractInfoDatabase[shc]
        line = shc_market_data_lines[shc][shc_market_line_index[shc]]
        date = fp.TokenizeToDate(contract, line)
        if (not last_date) or (dt.CompareDates(date, last_date) < 0):
            last_date = date

    return last_date
Exemplo n.º 2
0
def ReplayMarketData(shc_market_data_lines, shc_market_line_index, pm_list):
    print('Running sims for ' + str(pm_list))

    # oldest date
    last_date = FindOldestDate(shc_market_data_lines, shc_market_line_index)
    line_num = 0

    while True:
        if not last_date:
            break

        next_line = None
        next_shc = None
        next_date = last_date

        for shc in shc_market_data_lines.keys():
            if shc_market_line_index[shc] >= len(shc_market_data_lines[
                    shc]) - 1:  # -1 because of header in input
                # print('reached end of stream for ' + shc + ' skipping.')
                continue

            contract = ci.ContractInfoDatabase[shc]
            line = shc_market_data_lines[shc][shc_market_line_index[shc]]
            date = fp.TokenizeToDate(contract, line)
            # print('comparing ' + shc + ' date:' + date + ' & next_date:' + next_date)

            if dt.CompareDates(next_date, date) >= 0:
                next_line, next_shc, last_date, next_date = line, shc, date, date
                shc_market_line_index[shc] = shc_market_line_index[shc] + 1
                break

        if not next_shc:
            last_date = FindOldestDate(shc_market_data_lines,
                                       shc_market_line_index)
            continue

        for pm in pm_list:
            pm.OnMarketDataUpdate(next_shc, next_date, next_line)

        # print('next_line: ' + next_line.strip() + ' next_shc: ' + next_shc + ' last_date: ' + last_date)
        # print(shc_market_line_index)

    for shc in shc_market_data_lines.keys():
        shc_market_line_index[shc] = 0
Exemplo n.º 3
0
    def RecalibrateAllocations(self):
        if self.last_date_index >= len(self.all_dates):
            return

        # set index of how much data you're allowed to use to make predictions
        if dt.CompareDates(self.all_dates[self.last_date_index],
                           self.last_date) >= 0:
            return

        while dt.CompareDates(self.all_dates[self.last_date_index],
                              self.last_date) < 0:
            self.last_date_index += 1
            if self.last_date_index >= len(self.all_dates):
                return

        from sklearn import linear_model

        print('fitting ' + str(self.last_date) + ' index: ' +
              str(self.last_date_index))

        y_preds = []  # projected returns for each strategy
        # train giant model
        for reg in [linear_model.Lasso()]:
            # fit on all data before today
            for col in range(0, len(self.y[0])):
                x = self.x[0:self.last_date_index - 1]
                y = list(row[col]
                         for row in self.y[0:self.last_date_index - 1])

                reg.fit(x, y)

                y_pred = reg.predict([self.x[self.last_date_index]])
                y_preds.append(y_pred[0])

        from sklearn.metrics import explained_variance_score, mean_squared_error, r2_score
        exp_var = explained_variance_score(self.y[self.last_date_index],
                                           y_preds)
        mse = mean_squared_error(self.y[self.last_date_index], y_preds)
        r2 = r2_score(self.y[self.last_date_index], y_preds)
        print('prediction_stats: exp_var: ' + str(exp_var) + ' mse: ' +
              str(mse) + ' r2: ' + str(r2))

        trader_to_allocate = {}
        total_allocation = TOTAL_ALLOCATION
        sum_proj_pnl = 0
        for index in self.y_rev_legend:
            trader = self.y_rev_legend[index]

            if y_preds[index] < 0:
                self.alloc[trader] = MIN_ALLOCATION
                total_allocation -= MIN_ALLOCATION
            else:
                sum_proj_pnl += y_preds[index]
                trader_to_allocate[trader] = y_preds[index]

        for key in trader_to_allocate:
            self.alloc[key] = min(MAX_ALLOCATION,
                                  (trader_to_allocate[key] / sum_proj_pnl) *
                                  total_allocation)

        print(str(self.last_date) + ' allocs: ' + str(self.alloc))
Exemplo n.º 4
0
    def OnMarketDataUpdate(self, shc, date, line, risk_dollars):
        Trader.OnMarketDataUpdate(self, shc, date, line, risk_dollars)

        contract_index = (1 if shc == self.contracts[1] else 0)
        self.market_data[contract_index] = line
        if not all(self.market_data):
            return

        contracts = [
            ci.ContractInfoDatabase[self.contracts[0]],
            ci.ContractInfoDatabase[self.contracts[1]]
        ]
        contracts.append(
            ci.ContractInfo(contracts[0].Name + ' VS. ' + contracts[1].Name,
                            0.01, 10))

        date, open_price, high_price, low_price, close_price =\
          [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0]
        try:
            # unpack list
            for index in [0, 1]:
                date[index], open_price[index], high_price[index], low_price[index], close_price[index] =\
                  fp.TokenizeToPriceInfo(contracts[index], self.market_data[index])
        except ValueError or TypeError:
            return

        if dt.CompareDates(date[0], date[1]) != 0:
            return
        # print(str(self.market_data))

        for index in [0, 1]:
            self.lookback_prices[index].append(
                [high_price[index], low_price[index], close_price[index]])

        if len(self.lookback_prices[0]) < self.ma_lookback_days + 1:
            # not initialized yet, push and continue
            return

        # save ma and update list
        # print(list(row[2] for row in lookback_prices))
        ma, vol, dollar_vol, weight = [0, 0, 0], [0, 0, 0], [0, 0,
                                                             0], [1, 1, 1]
        for index in [0, 1]:
            ma[index] = statistics.mean(row[2]
                                        for row in self.lookback_prices[index])
            vol[index] = statistics.mean(
                abs(row[0] - row[1]) for row in self.lookback_prices[index])
            dollar_vol[index] = vol[index] * contracts[index].TickValue

        is_inverted = False  # maintain a flag if we invert ratio
        ratio = dollar_vol[0] / dollar_vol[1]
        if ratio < 1:
            ratio = 1 / ratio
            is_inverted = True

        high_price[2] = self.ComputeSpreadPrice(ratio, is_inverted,
                                                high_price[0], high_price[1])
        low_price[2] = self.ComputeSpreadPrice(ratio, is_inverted,
                                               low_price[0], low_price[1])
        close_price[2] = self.ComputeSpreadPrice(ratio, is_inverted,
                                                 close_price[0],
                                                 close_price[1])
        self.lookback_prices[2].append(
            [high_price[2], low_price[2], close_price[2]])
        ma[2] = statistics.mean(row[2] for row in self.lookback_prices[2])
        vol[2] = statistics.mean(
            abs(row[0] - row[1]) for row in self.lookback_prices[2])
        dev_from_ma = close_price[2] - ma[2]

        if self.log_level > 0:
            print('INFO vol ', vol, ' dollar vol ', dollar_vol, ' ratio ',
                  ratio)

        for index in [0, 1, 2]:
            if len(self.lookback_prices[index]) >= self.ma_lookback_days:
                self.lookback_prices[index].pop(0)

        loss_ticks = self.o_loss_ticks * vol[2]
        net_change = self.o_net_change * vol[2]

        # this is a tough one, and this solution is imperfect
        # but preferred for its simplicity
        spread_tick_value = min(contracts[0].TickValue,
                                contracts[1].TickValue * ratio)
        if is_inverted:
            spread_tick_value = min(contracts[0].TickValue * ratio,
                                    contracts[1].TickValue)

        if self.log_level > 0:
            print('INFO vol:',
                  vol,
                  'adjusted params:',
                  'net_change:',
                  net_change,
                  'loss_ticks:',
                  loss_ticks,
                  'spread_tick_value:',
                  spread_tick_value,
                  sep=' ')

        traded_today = False

        if self.my_position[
                2] == 0:  # flat, see if we want to get into a position
            # how much did today's close price deviate from moving average ?
            # +ve value means breaking out to the upside
            # -ve value means breaking out to the downside
            if abs(dev_from_ma) > net_change:  # blown out
                trade_size = int((risk_dollars / spread_tick_value) /
                                 loss_ticks + 1)
                self.my_position[0] = trade_size * (ratio
                                                    if is_inverted else 1)
                self.my_position[1] = trade_size * (1
                                                    if is_inverted else ratio)
                self.my_vwap = list(close_price)
                self.my_position[2] = trade_size * (1
                                                    if dev_from_ma < 0 else -1)
                self.my_vwap[2] = close_price[2]
                self.trades.append([
                    date[0], ('B' if dev_from_ma < 0 else 'S'), trade_size,
                    close_price[2], self.my_position[2], self.my_pnl[2],
                    vol[2], ma[2], dev_from_ma, high_price[2], low_price[2]
                ])
                traded_today = True

                if self.log_level > 0:
                    print('INFO initiating position ', self.trades[-1])
        else:  # have a position already, check for stop outs
            if ((self.my_position[2] > 0
                 and self.my_vwap[2] - low_price[2] > loss_ticks)
                    or (self.my_position[2] < 0
                        and high_price[2] - self.my_vwap[2] > loss_ticks)):
                stopout_price = self.my_vwap[2] +\
                                (loss_ticks * (1 if self.my_position[2] < 0 else -1))
                trade_pnl = abs(
                    self.my_position[2]) * loss_ticks * spread_tick_value
                self.my_pnl[2] -= trade_pnl
                buysell = ('S' if self.my_position[2] > 0 else 'B')

                self.trades.append([
                    date[0], buysell,
                    abs(self.my_position[2]), stopout_price, 0, self.my_pnl[2],
                    vol[2], ma[2], dev_from_ma, high_price[2], low_price[2]
                ])
                traded_today = True
                self.my_position = [0, 0, 0]

                if self.log_level > 0:
                    print('INFO stopped out ', self.trades[-1])
            elif abs(dev_from_ma) < 0.5 * net_change:  # trend dying out
                self.my_pnl[0] += self.my_position[0] * (
                    close_price[0] - self.my_vwap[0]) * contracts[0].TickValue
                self.my_pnl[1] += self.my_position[1] * (
                    close_price[1] - self.my_vwap[1]) * contracts[1].TickValue
                self.my_pnl[2] = self.my_pnl[0] + self.my_pnl[1]
                buysell = ('S' if self.my_position[2] > 0 else 'B')

                self.trades.append([
                    date[0], buysell,
                    abs(self.my_position[2]), close_price[2], 0,
                    self.my_pnl[2], vol[2], ma[2], dev_from_ma, high_price[2],
                    low_price[2]
                ])
                traded_today = True
                self.my_position = [0, 0, 0]

                if self.log_level > 0:
                    print('INFO took a win ', self.trades[-1])

        if not traded_today:
            unreal_pnl = self.my_position[0] * (close_price[0] - self.my_vwap[0]) * contracts[0].TickValue +\
                         self.my_position[1] * (close_price[1] - self.my_vwap[1]) * contracts [1].TickValue
            self.trades.append([
                date[0], '-', self.my_position[2], close_price[2], 0,
                self.my_pnl[2] + unreal_pnl, vol[2], ma[2], dev_from_ma,
                high_price[2], low_price[2]
            ])

        self.alloc.append(risk_dollars)
        if len(self.trades) >= 2:
            self.daily_pnl.append(self.trades[-1][5] - self.trades[-2][5])
            if self.trades[-2][5] != 0:
                self.pct_pnl_change.append(
                    100 * self.daily_pnl[-1] /
                    abs(self.trades[-2][5]))  # what % pnl increase?
        else:
            self.daily_pnl.append(self.trades[-1][5])
Exemplo n.º 5
0
    def OnMarketDataUpdate(self, shc, date, line, risk_dollars):
        Trader.OnMarketDataUpdate(self, shc, date, line, risk_dollars)

        contract_index = (1 if shc == self.contracts[1] else 0)
        self.market_data[contract_index] = line
        if not all(self.market_data):
            return

        contracts = [
            ci.ContractInfoDatabase[self.contracts[0]],
            ci.ContractInfoDatabase[self.contracts[1]]
        ]

        date, open_price, high_price, low_price, close_price =\
          [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0]
        try:
            # unpack list
            for index in [0, 1]:
                date[index], open_price[index], high_price[index], low_price[index], close_price[index] =\
                  fp.TokenizeToPriceInfo(contracts[index], self.market_data[index])
        except ValueError or TypeError:
            return

        if dt.CompareDates(date[0], date[1]) != 0:
            return
        # print(str(self.market_data))

        for index in [0, 1]:
            self.lookback_prices[index].append(
                [high_price[index], low_price[index], close_price[index]])

        if len(self.lookback_prices[0]) < self.ma_lookback_days + 1:
            # not initialized yet, push and continue
            return

        # save ma and update list
        # print(list(row[2] for row in lookback_prices))
        ma, vol, dev_from_ma = [0, 0], [0, 0], [0, 0]
        for index in [0, 1]:
            ma[index] = statistics.mean(row[2]
                                        for row in self.lookback_prices[index])
            vol[index] = statistics.mean(
                abs(row[0] - row[1]) for row in self.lookback_prices[index])
            dev_from_ma[index] = close_price[index] - ma[index]
            self.lookback_dev_from_ma[index].append(dev_from_ma[index])

        # Need at least 2 points, not enough degrees of freedom
        if len(self.lookback_dev_from_ma[0]) < 2:
            return

        corr = numpy.corrcoef(self.lookback_dev_from_ma[0],
                              self.lookback_dev_from_ma[1])
        cov = numpy.cov(self.lookback_dev_from_ma[0],
                        self.lookback_dev_from_ma[1])
        corr_0_1 = corr[0, 1]  # get the correlation between the 2 series

        # get the strength of the moves
        # this holds the answer to 'for every 1 unit move in B, how much should A move'
        # we will use this to predict expected moves and then use the difference
        # with actual move to accumulate positions
        cov_0_1 = cov[0, 0] / cov[0, 1]

        # project what the price-change should be
        # this is designed so that for weaker correlations, projections are dampened
        projected_dev_from_ma = dev_from_ma[1] * cov_0_1
        projected_price = ma[0] + projected_dev_from_ma
        dev_from_projection = projected_dev_from_ma * abs(
            corr_0_1) - dev_from_ma[0]
        if math.isnan(dev_from_projection):
            if self.log_level > 0:
                print('Skipping because dev_from_projection:',
                      dev_from_projection, 'or correlation:', corr_0_1,
                      'less than', self.min_correlation)
            return

        # track it so we know how big an average deviation is
        self.lookback_dev_from_projection.append(
            dev_from_projection)  # this measure only cares about the magnitude
        dev_from_projection_vol = statistics.mean(
            abs(item) for item in self.lookback_dev_from_projection)

        if self.log_level > 0:
            print('dev_from_projection',
                  dev_from_projection,
                  'dev_from_projection_vol',
                  dev_from_projection_vol,
                  'entries',
                  self.lookback_dev_from_projection,
                  sep=' ')

        if len(self.lookback_dev_from_ma[0]) < self.ma_lookback_days + 1:
            # need to have a long enough history
            # of relative deviations to project in the future
            if self.log_level > 0:
                print('not enough lookback_dev_from_ma history',
                      len(self.lookback_dev_from_ma[0]),
                      self.ma_lookback_days,
                      sep=' ')
            return

        for index in [0, 1]:
            while len(self.lookback_prices[index]) > self.ma_lookback_days:
                self.lookback_prices[index].pop(0)
            while len(
                    self.lookback_dev_from_ma[index]) > self.ma_lookback_days:
                self.lookback_dev_from_ma[index].pop(0)
        while len(self.lookback_dev_from_projection) > self.ma_lookback_days:
            self.lookback_dev_from_projection.pop(0)

        if self.log_level > 0:
            print(contracts[0].Name, 'projected by', contracts[1].Name,
                  'correlation:', corr_0_1, 'coefficient:', cov_0_1)
            print('projected_dev_from_ma',
                  projected_dev_from_ma,
                  'actual',
                  dev_from_ma[0],
                  'dev_from_projection',
                  dev_from_projection,
                  sep=' ')

        loss_ticks = self.o_loss_ticks * vol[0]
        net_change = self.o_net_change * dev_from_projection_vol

        if self.log_level > 0:
            print('INFO vol:',
                  vol,
                  'adjusted params:',
                  'net_change:',
                  net_change,
                  'loss_ticks:',
                  loss_ticks,
                  sep=' ')

        traded_today = False

        if self.my_position == 0:  # flat, see if we want to get into a position
            # how much did today's close price deviate from moving average ?
            # +ve value means breaking out to the upside
            # -ve value means breaking out to the downside
            if abs(dev_from_projection) > net_change:  # blown out
                trade_size = int((risk_dollars / contracts[0].TickValue) /
                                 loss_ticks + 1)
                self.my_position = trade_size * (1 if dev_from_projection > 0
                                                 else -1)
                self.my_vwap = close_price[0]
                self.trades.append([
                    date[0], ('B' if dev_from_projection > 0 else 'S'),
                    trade_size, close_price[0], self.my_position, self.my_pnl,
                    dev_from_projection_vol, ma[0], dev_from_projection,
                    projected_price, corr_0_1
                ])
                traded_today = True

                if self.log_level > 0:
                    print('INFO initiating position ', self.trades[-1])
        else:  # have a position already, check for stop outs
            if ((self.my_position > 0
                 and self.my_vwap - low_price[0] > loss_ticks)
                    or (self.my_position < 0
                        and high_price[0] - self.my_vwap > loss_ticks)):
                stopout_price = self.my_vwap +\
                                (loss_ticks * (1 if self.my_position < 0 else -1))
                trade_pnl = abs(
                    self.my_position) * loss_ticks * contracts[0].TickValue
                self.my_pnl -= trade_pnl
                buysell = ('S' if self.my_position > 0 else 'B')

                self.trades.append([
                    date[0], buysell,
                    abs(self.my_position), stopout_price, 0, self.my_pnl,
                    dev_from_projection_vol, ma[0], dev_from_projection,
                    projected_price, corr_0_1
                ])
                traded_today = True
                self.my_position = 0

                if self.log_level > 0:
                    print('INFO stopped out ', self.trades[-1])
            elif abs(dev_from_projection
                     ) < 0.5 * net_change:  # deviation dying out
                stopout_price = close_price[0]
                trade_pnl = self.my_position * (
                    stopout_price - self.my_vwap) * contracts[0].TickValue
                self.my_pnl += trade_pnl
                buysell = ('S' if self.my_position > 0 else 'B')

                self.trades.append([
                    date[0], buysell,
                    abs(self.my_position), stopout_price, 0, self.my_pnl,
                    vol[0], ma[0], dev_from_projection_vol, projected_price,
                    corr_0_1
                ])
                traded_today = True
                self.my_position = 0

                if self.log_level > 0:
                    print('INFO took a win ', self.trades[-1])

        if not traded_today:
            unreal_pnl = self.my_position * (
                close_price[0] - self.my_vwap) * contracts[0].TickValue
            self.trades.append([
                date[0], '-', self.my_position, close_price[0], 0,
                self.my_pnl + unreal_pnl, dev_from_projection_vol, ma[0],
                dev_from_projection, projected_price, corr_0_1
            ])

        self.alloc.append(risk_dollars)
        if len(self.trades) >= 2:
            self.daily_pnl.append(self.trades[-1][5] - self.trades[-2][5])
            if self.trades[-2][5] != 0:
                self.pct_pnl_change.append(
                    100 * self.daily_pnl[-1] /
                    abs(self.trades[-2][5]))  # what % pnl increase?
        else:
            self.daily_pnl.append(self.trades[-1][5])

        if self.log_level > 0:
            print('TRADE ' + str(self.ShortName()) + ' ' +
                  str(self.trades[-1]))
            print('ALLOC ' + str(self.ShortName()) + ' ' + str(self.alloc[-1]))