Beispiel #1
0
    def __init__(self, dataHandler,
                 events,
                 startDate,
                 assets,
                 initialCapital=100000.0,
                 benchmark=None,
                 portfolioType=PortfolioType.CashManageable):
        self.dataHandler = dataHandler
        self.events = events
        self.allTradableAssets = self.dataHandler.allTradableAssets
        self.startDate = startDate
        self.initialCapital = initialCapital
        self.benchmark = benchmark
        self.assets = assets
        self.positionsBook = StocksPositionsBook(assets)
        self.portfolioType = portfolioType

        self.allPositions = self.constructAllPositions()
        self.currentPosition = defaultdict(int, [(s, 0) for s in self.allTradableAssets])

        self.allHoldings = [] # self.constructAllHoldings()
        self.currentHoldings = self.constructCurrentHoldings()

        self.orderBook = None

        vp_settings.set_source(Settings.data_source)
Beispiel #2
0
    def __init__(self, dataHandler,
                 events,
                 startDate,
                 assets,
                 initialCapital=100000.0,
                 benchmark=None,
                 portfolioType=PortfolioType.CashManageable):
        self.dataHandler = dataHandler
        self.events = events
        self.allTradableAssets = self.dataHandler.allTradableAssets
        self.startDate = startDate
        self.initialCapital = initialCapital
        self.benchmark = benchmark
        self.assets = assets
        self.positionsBook = StocksPositionsBook(assets)
        self.portfolioType = portfolioType

        self.allPositions = self.constructAllPositions()
        self.currentPosition = defaultdict(int, [(s, 0) for s in self.allTradableAssets])

        self.allHoldings = [] # self.constructAllHoldings()
        self.currentHoldings = self.constructCurrentHoldings()

        self.orderBook = None

        vp_settings.set_source(Settings.data_source)
Beispiel #3
0
    def __init__(self, dataHandler,
                 events,
                 startDate,
                 assets,
                 initialCapital=100000.0,
                 benchmark=None,
                 portfolioType=PortfolioType.CashManageable):
        self.dataHandler = dataHandler
        self.events = events
        self.tradableAssets = self.dataHandler.tradableAssets
        self.startDate = startDate
        self.initialCapital = initialCapital
        self.benchmark = benchmark
        self.assets = assets
        self.positionsBook = StocksPositionsBook(assets)
        self.portfolioType = portfolioType

        self.allPositions = self.constructAllPositions()
        self.currentPosition = dict((s, 0) for s in self.tradableAssets)

        self.allHoldings = self.constructAllHoldings()
        self.currentHoldings = self.constructCurrentHoldings()
Beispiel #4
0
class Portfolio(object):

    def __init__(self, dataHandler,
                 events,
                 startDate,
                 assets,
                 initialCapital=100000.0,
                 benchmark=None,
                 portfolioType=PortfolioType.CashManageable):
        self.dataHandler = dataHandler
        self.events = events
        self.allTradableAssets = self.dataHandler.allTradableAssets
        self.startDate = startDate
        self.initialCapital = initialCapital
        self.benchmark = benchmark
        self.assets = assets
        self.positionsBook = StocksPositionsBook(assets)
        self.portfolioType = portfolioType

        self.allPositions = self.constructAllPositions()
        self.currentPosition = defaultdict(int, [(s, 0) for s in self.allTradableAssets])

        self.allHoldings = [] # self.constructAllHoldings()
        self.currentHoldings = self.constructCurrentHoldings()

        self.orderBook = None

        vp_settings.set_source(Settings.data_source)

    def constructAllPositions(self):
        d = dict((k, v) for k, v in [(s, 0) for s in self.allTradableAssets])
        d['datetime'] = self.startDate
        return [d]

    def constructAllHoldings(self):
        d = dict((k, v) for k, v in [(s, 0) for s in self.allTradableAssets])
        d['datetime'] = self.startDate
        d['cash'] = self.initialCapital
        d['margin'] = 0.0
        d['commission'] = 0.0
        d['pnl'] = 0.
        d['total'] = self.initialCapital
        return [d]

    def constructCurrentHoldings(self):
        d = dict((k, v) for k, v in [(s, 0) for s in self.allTradableAssets])
        d['datetime'] = self.startDate
        d['cash'] = self.initialCapital
        d['margin'] = 0.0
        d['commission'] = 0.0
        d['pnl'] = 0.
        d['total'] = self.initialCapital
        return d

    def updateTimeindex(self):
        latestDatetime = self.dataHandler.currentTimeIndex

        dh = dict((s, 0) for s in self.allTradableAssets)
        dh['datetime'] = latestDatetime
        dh['cash'] = self.currentHoldings['cash']
        dh['commission'] = self.currentHoldings['commission']
        dh['margin'] = 0.
        dh['total'] = self.currentHoldings['total']
        dh['pnl'] = self.currentHoldings['pnl']

        for s in self.allTradableAssets:
            bookValue = 0.
            bookPnL = 0.
            margin = 0.
            if self.currentPosition[s]:
                currentCost = self.dataHandler.getLatestBarValue(s, 'close') * self.assets[s].multiplier
                bookValue, bookPnL, margin = self.positionsBook.getBookValueAndBookPnL(s, currentCost)
            dh[s] = bookValue
            dh['margin'] += margin
            dh['pnl'] += bookPnL
            dh['total'] += bookPnL

        self.allHoldings.append(dh)

    def updatePositionFromFill(self, fill):
        fillDir = fill.direction
        if fillDir == OrderDirection.BUY or fillDir == OrderDirection.BUY_BACK:
            self.currentPosition[fill.symbol] += fill.quantity
        else:
            self.currentPosition[fill.symbol] -= fill.quantity

    def updateHoldingsFromFill(self, fill, pnl):
        self.currentHoldings[fill.symbol] += fill.fillCost
        self.currentHoldings['commission'] += fill.commission
        if not isClose(fill.fillCost, 0.):
            self.currentHoldings['cash'] -= (fill.fillCost + fill.commission)
        else:
            self.currentHoldings['cash'] += (pnl - fill.commission)
        self.currentHoldings['pnl'] += pnl - fill.commission
        self.currentHoldings['total'] += pnl - fill.commission

        fillDir = fill.direction
        if fillDir == OrderDirection.BUY_BACK or fillDir == OrderDirection.SELL_SHORT:
            self.currentHoldings['margin'] -= fill.fillCost

    def updateFill(self, event):
        posClosed, posOpen, pnl = self.positionsBook.updatePositionsByFill(event)
        self.updatePositionFromFill(event)
        self.updateHoldingsFromFill(event, pnl)

        self.filledBook.updateFromFillEvent(event)

    def cancelOrders(self, timeIndex, posBook):
        self.orderBook.cancelOrders(timeIndex, posBook)

    def generateNaiveOrder(self, signal):
        order = None

        symbol = signal.symbol
        direction = signal.signalType

        mktQuantity = signal.quantity
        curQuantity = self.currentPosition[symbol]
        orderType = 'MKT'

        if direction == 'LONG' and curQuantity == 0:
            order = OrderEvent(symbol, orderType, mktQuantity, 1)
        if direction == 'SHORT' and curQuantity == 0:
            order = OrderEvent(symbol, orderType, mktQuantity, -1)

        if direction == 'EXIT' and curQuantity > 0:
            order = OrderEvent(symbol, orderType, abs(curQuantity), -1)
        if direction == 'EXIT' and curQuantity < 0:
            order = OrderEvent(symbol, orderType, abs(curQuantity), 1)

        return order

    def updateSignal(self, event):
        if event.type == 'SIGNAL':
            orderEvent = self.generateNaiveOrder(event)
            self.events.put(orderEvent)

    def _createFullNotionalEquityCurve(self, curve):
        rawpos = curve.drop(['cash', 'commission', 'total', 'margin', 'pnl'], axis=1)
        notionals = rawpos.abs().sum(axis=1).fillna(0)
        notional_directions = rawpos.sum(axis=1).fillna(0).apply(sign)
        pnldiffs = curve['pnl'].diff()
        # to handl the case when pnl is shown in null notional day
        cumPnL = 0.
        returns = []
        for notional, pnldiff, direction in zip(notionals, pnldiffs, notional_directions):
            if not isClose(notional):
                r = direction * np.log(direction * notional / (direction * notional - pnldiff - cumPnL))
                returns.append(r)
                cumPnL = 0.
            elif not np.isnan(pnldiff):
                returns.append(0.)
                cumPnL += pnldiff
            else:
                returns.append(0.)
        curve['return'] = returns
        curve.fillna(0., inplace=True)
        curve['equity_curve'] = np.exp(curve['return'].cumsum())

    def createEquityCurveDataframe(self):
        curve = pd.DataFrame(self.allHoldings)
        curve.set_index('datetime', inplace=True)
        if self.portfolioType == PortfolioType.FullNotional:
            self._createFullNotionalEquityCurve(curve)
        else:
            curve['return'] = np.log(curve['total'] / curve['total'].shift(1))
            curve.dropna(inplace=True)
            curve['equity_curve'] = np.exp(curve['return'].cumsum())
        self.equityCurve = curve.dropna()

    def outputSummaryStats(self, curve, other_curves, plot):
        returns = curve['return']
        if hasattr(self.dataHandler, "benchmarkData"):
            benchmarkReturns = self.dataHandler.benchmarkData['return']
            benchmarkReturns.name = self.benchmark
        else:
            benchmarkReturns = None

        perf_metric, perf_df, rollingRisk = createPerformanceTearSheet(returns=returns,
                                                                       benchmarkReturns=benchmarkReturns,
                                                                       other_curves=other_curves,
                                                                       plot=plot)

        if self.portfolioType == PortfolioType.FullNotional:
            positons = curve.drop(['cash', 'commission', 'total', 'return', 'margin', 'equity_curve', 'pnl'], axis=1)
        else:
            positons = curve.drop(['commission', 'total', 'return', 'margin', 'equity_curve', 'pnl'], axis=1)
        aggregated_positons = createPostionTearSheet(positons, plot=plot)

        transactions = extractTransactionFromFilledBook(self.filledBook.view())

        if hasattr(self.dataHandler, "_freq"):

            if self.dataHandler._freq == 0:
                freq = 'M'
            else:
                freq = 'D'

            turnover_rate = createTranscationTearSheet(transactions, positons, freq=freq, plot=plot)
        else:
            turnover_rate = createTranscationTearSheet(transactions, positons, plot=plot)

        if plot:
            plt.show()

        return perf_metric, perf_df, rollingRisk, aggregated_positons, transactions, turnover_rate
Beispiel #5
0
class Portfolio(object):

    def __init__(self, dataHandler,
                 events,
                 startDate,
                 assets,
                 initialCapital=100000.0,
                 benchmark=None,
                 portfolioType=PortfolioType.CashManageable):
        self.dataHandler = dataHandler
        self.events = events
        self.tradableAssets = self.dataHandler.tradableAssets
        self.startDate = startDate
        self.initialCapital = initialCapital
        self.benchmark = benchmark
        self.assets = assets
        self.positionsBook = StocksPositionsBook(assets)
        self.portfolioType = portfolioType

        self.allPositions = self.constructAllPositions()
        self.currentPosition = defaultdict(int, [(s, 0) for s in self.tradableAssets])

        self.allHoldings = self.constructAllHoldings()
        self.currentHoldings = self.constructCurrentHoldings()

        vp_settings.set_source(Settings.data_source)

    def constructAllPositions(self):
        d = dict((k, v) for k, v in [(s, 0) for s in self.tradableAssets])
        d['datetime'] = self.startDate
        return [d]

    def constructAllHoldings(self):
        d = dict((k, v) for k, v in [(s, 0) for s in self.tradableAssets])
        d['datetime'] = self.startDate
        d['cash'] = self.initialCapital
        d['margin'] = 0.0
        d['commission'] = 0.0
        d['pnl'] = 0.
        d['total'] = self.initialCapital
        return [d]

    def constructCurrentHoldings(self):
        d = dict((k, v) for k, v in [(s, 0) for s in self.tradableAssets])
        d['datetime'] = self.startDate
        d['cash'] = self.initialCapital
        d['margin'] = 0.0
        d['commission'] = 0.0
        d['pnl'] = 0.
        d['total'] = self.initialCapital
        return d

    def updateTimeindex(self):
        latestDatetime = self.dataHandler.currentTimeIndex

        dh = dict((s, 0) for s in self.tradableAssets)
        dh['datetime'] = latestDatetime
        dh['cash'] = self.currentHoldings['cash']
        dh['commission'] = self.currentHoldings['commission']
        dh['margin'] = self.currentHoldings['margin']
        dh['total'] = self.currentHoldings['total']
        dh['pnl'] = self.currentHoldings['pnl']

        for s in self.tradableAssets:
            bookValue = 0.
            bookPnL = 0.
            if self.currentPosition[s]:
                currentCost = self.dataHandler.getLatestBarValue(s, 'close') * self.assets[s].multiplier
                bookValue, bookPnL = self.positionsBook.getBookValueAndBookPnL(s, currentCost)
            dh[s] = bookValue
            dh['pnl'] += bookPnL
            dh['total'] += bookPnL

        self.allHoldings.append(dh)

    def updatePositionFromFill(self, fill):
        fillDir = fill.direction
        self.currentPosition[fill.symbol] += fillDir * fill.quantity

    def updateHoldingsFromFill(self, fill, pnl):
        self.currentHoldings[fill.symbol] += fill.fillCost
        self.currentHoldings['commission'] += fill.commission
        if not isClose(fill.fillCost, 0.):
            self.currentHoldings['cash'] -= (fill.fillCost + fill.commission)
        else:
            self.currentHoldings['cash'] += (pnl - fill.commission)
        self.currentHoldings['pnl'] += pnl - fill.commission
        self.currentHoldings['total'] += pnl - fill.commission

    def updateFill(self, event):
        posClosed, posOpen, pnl = self.positionsBook.updatePositionsByFill(event)
        self.updatePositionFromFill(event)
        self.updateHoldingsFromFill(event, pnl)

        self.filledBook.updateFromFillEvent(event)

    def generateNaiveOrder(self, signal):
        order = None

        symbol = signal.symbol
        direction = signal.signalType

        mktQuantity = signal.quantity
        curQuantity = self.currentPosition[symbol]
        orderType = 'MKT'

        if direction == 'LONG' and curQuantity == 0:
            order = OrderEvent(symbol, orderType, mktQuantity, 1)
        if direction == 'SHORT' and curQuantity == 0:
            order = OrderEvent(symbol, orderType, mktQuantity, -1)

        if direction == 'EXIT' and curQuantity > 0:
            order = OrderEvent(symbol, orderType, abs(curQuantity), -1)
        if direction == 'EXIT' and curQuantity < 0:
            order = OrderEvent(symbol, orderType, abs(curQuantity), 1)

        return order

    def updateSignal(self, event):
        if event.type == 'SIGNAL':
            orderEvent = self.generateNaiveOrder(event)
            self.events.put(orderEvent)

    def _createFullNotionalEquityCurve(self, curve):
        rawpos = curve.drop(['cash', 'commission', 'total', 'margin', 'pnl'], axis=1)
        notionals = rawpos.abs().sum(axis=1).fillna(0)
        notional_directions = rawpos.sum(axis=1).fillna(0).apply(sign)
        pnldiffs = curve['pnl'].diff()
        # to handl the case when pnl is shown in null notional day
        cumPnL = 0.
        returns = []
        for notional, pnldiff, direction in zip(notionals, pnldiffs, notional_directions):
            if not isClose(notional):
                r = direction * np.log(direction * notional / (direction * notional - pnldiff - cumPnL))
                returns.append(r)
                cumPnL = 0.
            elif not np.isnan(pnldiff):
                returns.append(0.)
                cumPnL += pnldiff
            else:
                returns.append(0.)
        curve['return'] = returns
        curve.fillna(0., inplace=True)
        curve['equity_curve'] = np.exp(curve['return'].cumsum())

    def createEquityCurveDataframe(self):
        curve = pd.DataFrame(self.allHoldings)
        curve.set_index('datetime', inplace=True)
        if self.portfolioType == PortfolioType.FullNotional:
            self._createFullNotionalEquityCurve(curve)
        else:
            curve['return'] = np.log(curve['total'] / curve['total'].shift(1))
            curve.dropna(inplace=True)
            curve['equity_curve'] = np.exp(curve['return'].cumsum())
        self.equityCurve = curve.dropna()

    def outputSummaryStats(self, curve, plot):
        returns = curve['return']
        if hasattr(self.dataHandler, "benchmarkData"):
            benchmarkReturns = self.dataHandler.benchmarkData['return']
            benchmarkReturns.name = self.benchmark
        else:
            benchmarkReturns = None
        perf_metric, perf_df, rollingRisk = createPerformanceTearSheet(returns=returns, benchmarkReturns=benchmarkReturns, plot=plot)

        if self.portfolioType == PortfolioType.FullNotional:
            positons = curve.drop(['cash', 'commission', 'total', 'return', 'margin', 'equity_curve', 'pnl'], axis=1)
        else:
            positons = curve.drop(['commission', 'total', 'return', 'margin', 'equity_curve', 'pnl'], axis=1)
        aggregated_positons = createPostionTearSheet(positons, plot=plot)

        transactions = extractTransactionFromFilledBook(self.filledBook.view())
        turnover_rate = createTranscationTearSheet(transactions, positons, plot=plot)

        if plot:
            plt.show()

        return perf_metric, perf_df, rollingRisk, aggregated_positons, transactions, turnover_rate
 def setUp(self):
     assets = {'600000': XSHGStock, 'IF1501': IndexFutures}
     self.positionsBook = StocksPositionsBook(assets)
class TestPositionsBook(unittest.TestCase):
    def setUp(self):
        assets = {'600000': XSHGStock, 'IF1501': IndexFutures}
        self.positionsBook = StocksPositionsBook(assets)

    def testUpdatedFromOrder(self):
        self.positionsBook.updatePositionsByOrder('600000',
                                                  dt.date(2015, 11, 16), 100,
                                                  1)
        self.assertEqual(self.positionsBook._allPositions, {})

    def testUpdatedFromFillEvent(self):
        self.positionsBook.updatePositionsByFill('600000',
                                                 dt.date(2015, 11, 16), 100, 1)
        self.assertEqual(self.positionsBook._allPositions['600000'],
                         ([dt.date(2015, 11, 16)], [100], [0], [1]))

    def testUpdatedFromOrderWithNonEmptyPositionBook(self):
        self.positionsBook.updatePositionsByFill('600000',
                                                 dt.date(2015, 11, 13), 300, 1)
        self.assertEqual(
            self.positionsBook.avaliableForTrade('600000',
                                                 dt.date(2015, 11, 16)),
            (300, 0))

        self.positionsBook.updatePositionsByOrder('600000',
                                                  dt.date(2015, 11, 16), 100,
                                                  -1)
        self.assertEqual(self.positionsBook._allPositions['600000'],
                         ([dt.date(2015, 11, 13)], [300], [100], [1]))
        self.assertEqual(
            self.positionsBook.avaliableForTrade('600000',
                                                 dt.date(2015, 11, 16)),
            (200, 0))

    def testUpdatedSellShortOrderWithShortForbiddenAsset(self):
        with self.assertRaises(ValueError):
            self.positionsBook.updatePositionsByOrder('600000',
                                                      dt.date(2015, 11, 16),
                                                      100, -1)

    def testUpdatedSellShortOrderWithShortAllowedAsset(self):
        self.positionsBook.updatePositionsByOrder('IF1501',
                                                  dt.date(2015, 11, 16), 100,
                                                  -1)

    def testUpdatedFromFillWithBothLongAndShot(self):
        self.positionsBook.updatePositionsByOrder('IF1501',
                                                  dt.date(2015, 11, 13), 1, -1)
        self.positionsBook.updatePositionsByFill('IF1501',
                                                 dt.date(2015, 11, 13), 1, -1)
        self.assertEqual(
            self.positionsBook.avaliableForTrade('IF1501',
                                                 dt.date(2015, 11, 13)),
            (0, 1))
        self.positionsBook.updatePositionsByOrder('IF1501',
                                                  dt.date(2015, 11, 16), 2, 1)
        self.positionsBook.updatePositionsByFill('IF1501',
                                                 dt.date(2015, 11, 16), 1, 1)
        self.positionsBook.updatePositionsByFill('IF1501',
                                                 dt.date(2015, 11, 16), 1, 1)
        self.assertEqual(self.positionsBook._allPositions['IF1501'],
                         ([dt.date(2015, 11, 16)], [1], [0], [1]))
 def setUp(self):
     assets = {'600000': XSHGStock,
               'IF1501': IndexFutures}
     self.positionsBook = StocksPositionsBook(assets)
class TestPositionsBook(unittest.TestCase):

    def setUp(self):
        assets = {'600000': XSHGStock,
                  'IF1501': IndexFutures}
        self.positionsBook = StocksPositionsBook(assets)

    def testUpdatedFromOrder(self):
        self.positionsBook.updatePositionsByOrder('600000', dt.date(2015, 11, 16), 100, 1)
        self.assertEqual(self.positionsBook._allPositions, {})

    def testUpdatedFromFillEvent(self):
        self.positionsBook.updatePositionsByFill('600000', dt.date(2015, 11, 16), 100, 1)
        self.assertEqual(self.positionsBook._allPositions['600000'], ([dt.date(2015, 11, 16)],
                                                                      [100],
                                                                      [0],
                                                                      [1]))

    def testUpdatedFromOrderWithNonEmptyPositionBook(self):
        self.positionsBook.updatePositionsByFill('600000', dt.date(2015, 11, 13), 300, 1)
        self.assertEqual(self.positionsBook.avaliableForTrade('600000', dt.date(2015, 11, 16)), (300, 0))

        self.positionsBook.updatePositionsByOrder('600000', dt.date(2015, 11, 16), 100, -1)
        self.assertEqual(self.positionsBook._allPositions['600000'],  ([dt.date(2015, 11, 13)],
                                                                       [300],
                                                                       [100],
                                                                       [1]))
        self.assertEqual(self.positionsBook.avaliableForTrade('600000', dt.date(2015, 11, 16)), (200, 0))

    def testUpdatedSellShortOrderWithShortForbiddenAsset(self):
        with self.assertRaises(ValueError):
            self.positionsBook.updatePositionsByOrder('600000', dt.date(2015, 11, 16), 100, -1)

    def testUpdatedSellShortOrderWithShortAllowedAsset(self):
        self.positionsBook.updatePositionsByOrder('IF1501', dt.date(2015, 11, 16), 100, -1)

    def testUpdatedFromFillWithBothLongAndShot(self):
        self.positionsBook.updatePositionsByOrder('IF1501', dt.date(2015, 11, 13), 1, -1)
        self.positionsBook.updatePositionsByFill('IF1501', dt.date(2015, 11, 13), 1, -1)
        self.assertEqual(self.positionsBook.avaliableForTrade('IF1501', dt.date(2015, 11, 13)), (0, 1))
        self.positionsBook.updatePositionsByOrder('IF1501', dt.date(2015, 11, 16), 2, 1)
        self.positionsBook.updatePositionsByFill('IF1501', dt.date(2015, 11, 16), 1, 1)
        self.positionsBook.updatePositionsByFill('IF1501', dt.date(2015, 11, 16), 1, 1)
        self.assertEqual(self.positionsBook._allPositions['IF1501'], ([dt.date(2015, 11, 16)],
                                                                       [1],
                                                                       [0],
                                                                       [1]))