Ejemplo n.º 1
0
    def idx_of_first_trade_next_30days(self, tradetomatch):
        ## Return index of first trade done after this trade, with opposite sign, and within 30 days

        self.date_sort()

        tradedatetime = tradetomatch.Date

        listdatetimes = [trade.Date for trade in self]
        listdates = [x.date() for x in listdatetimes]

        tradedate30daysafter = tradetomatch.Date.date() + datetime.timedelta(
            30)
        listsignquant = [trade.SignQuantity for trade in self]

        ## trades are in next 30 days or today, but not in the past
        ## and with opposite sign
        next_30days_trades = [
            idx for idx in range(len(listdates))
            if listdates[idx] <= tradedate30daysafter
            and listdatetimes[idx] > tradedatetime
            and not signs_match(listsignquant[idx], tradetomatch.SignQuantity)
        ]

        if len(next_30days_trades) == 0:
            return None

        ## Return the first trade
        return next_30days_trades[0]
    def spawn_pseudo_trades(self, tradetoclose):
        """
        Returns a new clone trade with tradetoclose, and a residual clone trade
        
        """
        assert self._ready_for_split()
        assert not self.pseudotrade
        
        oldquantity=copy(self.SignQuantity)
        
        residualtrade=oldquantity - tradetoclose

        assert type(tradetoclose) is float
        assert signs_match(tradetoclose, oldquantity)
        assert abs(tradetoclose)<=abs(oldquantity)
        assert abs(tradetoclose)>0.0
        
        neworder=self._share_of_trade(share=tradetoclose)
        changedorder=self._share_of_trade(share=residualtrade)
        
        neworder.modify(tradetype="Close")
        changedorder.modify(tradetype="Open")
        
        neworder.modify(pseudotrade=True)
        changedorder.modify(pseudotrade=True)

        oldtradeid=self.TradeID
        neworder.modify(TradeID=oldtradeid+":1")
        changedorder.modify(TradeID=oldtradeid+":2")
        
        ## To avoid duplications we make the opening order a second after the old one
        newdate=changedorder.Date+datetime.timedelta(seconds=1)
        changedorder.modify(Date=newdate)
        
        return [changedorder, neworder]
Ejemplo n.º 3
0
    def idx_of_last_trade_same_day(self, tradetomatch):
        ## Return indices of trades with same date, executed prior to this trade, with opposite sign

        tradedatetime = tradetomatch.Date

        self.date_sort()

        tradedate = tradedatetime.date()

        listdatetimes = [trade.Date for trade in self]
        listdates = [x.date() for x in listdatetimes]
        listsignquant = [trade.SignQuantity for trade in self]

        ## done on same day, but not in future
        ## Future trades on same day will be picked up in 'within 30 days' rule
        same_day_trades = [
            idx for idx in range(len(listdates)) if listdates[idx] == tradedate
            and listdatetimes[idx] < tradedatetime
            and not signs_match(listsignquant[idx], tradetomatch.SignQuantity)
        ]

        if len(same_day_trades) == 0:
            return None

        return same_day_trades[-1]
    def idx_of_first_trade_next_30days(self, tradetomatch):
        ## Return index of first trade done after this trade, with opposite sign, and within 30 days 

        self.date_sort()

        tradedatetime=tradetomatch.Date

        listdatetimes=[trade.Date for trade in self]
        listdates=[x.date() for x in listdatetimes]

        tradedate30daysafter=trade.Date.date()+datetime.timedelta(30)
        listsignquant=[trade.SignQuantity for trade in self]


        ## trades are in next 30 days or today, but not in the past
        ## and with opposite sign
        next_30days_trades=[idx for idx in range(len(listdates)) 
                            if listdates[idx]<=tradedate30daysafter and listdatetimes[idx]>tradedatetime
                            and not signs_match(listsignquant[idx], tradetomatch.SignQuantity)]

        if len(next_30days_trades)==0:
            return None

        ## Return the first trade
        return next_30days_trades[0]
    def _share_of_trade(self, share=None, pro_rata=None):
        """
        Returns a trade, a clones of self, with quantity share or a pro_rata proportion
        
        """
        
        assert not (share is None and pro_rata is None)
        
        newtrade=copy(self)
        oldquantity=copy(self.SignQuantity)

        if pro_rata is None:
            assert type(share) is float
            assert signs_match(share, oldquantity)
            assert abs(share)<=abs(oldquantity)

            pro_rata=share/oldquantity

        if share is None:
            assert type(pro_rata) is float 
            assert pro_rata>=0.0 and pro_rata<=1.0

            share=oldquantity*pro_rata

        if pro_rata==0.0:
            newtrade.modify(Value=0.0, Commission=0.0, Tax=0.0, 
                            SignQuantity=0.0, Quantity=0.0,   
                            )
        else:
            newtrade.modify(Value=self.Value*pro_rata, Commission=self.Commission*pro_rata, Tax=self.Tax*pro_rata, 
                            SignQuantity=share, Quantity=abs(share),   
                            )
        
        return newtrade
    def spawn_pseudo_trades(self, tradetoclose):
        """
        Returns a new clone trade with tradetoclose, and a residual clone trade
        
        """
        assert self._ready_for_split()
        assert not self.pseudotrade
        
        oldquantity=copy(self.SignQuantity)
        
        residualtrade=oldquantity - tradetoclose

        assert type(tradetoclose) is float
        assert signs_match(tradetoclose, oldquantity)
        assert abs(tradetoclose)<=abs(oldquantity)
        assert abs(tradetoclose)>0.0
        
        neworder=self._share_of_trade(share=tradetoclose)
        changedorder=self._share_of_trade(share=residualtrade)
        
        neworder.modify(tradetype="Close")
        changedorder.modify(tradetype="Open")
        
        neworder.modify(pseudotrade=True)
        changedorder.modify(pseudotrade=True)

        oldtradeid=self.TradeID
        neworder.modify(TradeID=oldtradeid+":1")
        changedorder.modify(TradeID=oldtradeid+":2")
        
        ## To avoid duplications we make the opening order a second after the old one
        newdate=changedorder.Date+datetime.timedelta(seconds=1)
        changedorder.modify(Date=newdate)
        
        return [changedorder, neworder]
    def _share_of_trade(self, share=None, pro_rata=None):
        """
        Returns a trade, a clones of self, with quantity share or a pro_rata proportion
        
        """
        
        assert not (share is None and pro_rata is None)
        
        newtrade=copy(self)
        oldquantity=copy(self.SignQuantity)

        if pro_rata is None:
            assert type(share) is float
            assert signs_match(share, oldquantity)
            assert abs(share)<=abs(oldquantity)

            pro_rata=share/oldquantity

        if share is None:
            assert type(pro_rata) is float 
            assert pro_rata>=0.0 and pro_rata<=1.0

            share=oldquantity*pro_rata

        if pro_rata==0.0:
            newtrade.modify(Value=0.0, Commission=0.0, Tax=0.0, 
                            SignQuantity=0.0, Quantity=0.0,   
                            )
        else:
            newtrade.modify(Value=self.Value*pro_rata, Commission=self.Commission*pro_rata, Tax=self.Tax*pro_rata, 
                            SignQuantity=share, Quantity=abs(share),   
                            )
        
        return newtrade
    def _proportionate_pop_idx(self, tradeidxlist, totaltopop):
        """
        Reduce all trades in tradeidxlist by a proportion
        
        """

        old_final_position=copy(self.final_position())
        old_trade_count=copy(len(self))
        
        if not all([trade._has_allocation_data() for trade in self]):
            raise Exception("You can't add spawn pseudo trades without _add_cumulative_data first")

        original_trades_to_trim=TradeList([self[idx] for idx in tradeidxlist])
        
        total_in_list=original_trades_to_trim.final_position()
        
        assert signs_match(totaltopop, total_in_list)
        
        pro_rata=totaltopop/total_in_list
        
        residual = 1.0 - pro_rata
        
        if abs(residual)<THRESHOLD:
            residual=0.0
            pro_rata=1.0
            
        ## Returns list of tuples (parent, child)
        tradetuplelist=TradeList([tradetopop.spawn_child_trade(pro_rata=pro_rata) for tradetopop in original_trades_to_trim])

        ## remove original trades
        for trade in original_trades_to_trim:
            ## find matching trade (can't use original indices since will change with size of list)
            trade_idx=[idx for idx in range(len(self)) if self[idx]==trade]
            assert len(trade_idx)==1
            
            self.pop(trade_idx[0])

                    
        popped_trades=TradeList([tradetuple[1] for tradetuple in tradetuplelist])
        assert abs(totaltopop - popped_trades.final_position())<THRESHOLD

        ## Residual left behind...
        if residual>0.0:
            ## Put residual parent trades back in
            [self.append(tradetuple[0]) for tradetuple in tradetuplelist]

            assert len(self) == old_trade_count

        else:
            ## No residual trades, just pop in their entirity
            ## We've permanently lost these trades
            assert (len(self) + len(popped_trades)) == old_trade_count 

        self.date_sort()
        
        assert abs(self.final_position()+totaltopop - old_final_position)<THRESHOLD
        
        return popped_trades
Ejemplo n.º 9
0
    def _partial_pop_idx(self, tradeidx, maxtopop):
        """
        Pop the trade tradeidx, up to a limit of maxtopop

        If this trade is too big then leave behind a residual trade

        Returns the trade
        """
        old_final_position = copy(self.final_position())
        old_trade_count = copy(len(self))

        if not all([trade._has_allocation_data() for trade in self]):
            raise Exception(
                "You can't add spawn pseudo trades without _add_cumulative_data first"
            )

        tradetopop = self[tradeidx]

        assert signs_match(tradetopop.SignQuantity, maxtopop)

        if abs(tradetopop.SignQuantity) <= abs(maxtopop):
            ## Pop the entire trade
            finaltradetopop = self.pop(tradeidx)
            assert (len(self) + 1) == old_trade_count

        else:
            ## Pop part of the trade, by spawing a child order
            (parent_trade,
             finaltradetopop) = tradetopop.spawn_child_trade(share=maxtopop)

            ## Remove the original trade
            self.pop(tradeidx)

            ## Add the residual trade
            self.append(parent_trade)

            assert len(self) == old_trade_count

        self.date_sort()

        assert abs(self.final_position() + finaltradetopop.SignQuantity -
                   old_final_position) < THRESHOLD

        return finaltradetopop
    def _partial_pop_idx(self, tradeidx, maxtopop):
        """
        Pop the trade tradeidx, up to a limit of maxtopop
        
        If this trade is too big then leave behind a residual trade
        
        Returns the trade
        """
        old_final_position=copy(self.final_position())
        old_trade_count=copy(len(self))
        
        if not all([trade._has_allocation_data() for trade in self]):
            raise Exception("You can't add spawn pseudo trades without _add_cumulative_data first")
        
        tradetopop=self[tradeidx]
        
        
        
        assert signs_match(tradetopop.SignQuantity, maxtopop)
        
        if abs(tradetopop.SignQuantity)<=abs(maxtopop):
            ## Pop the entire trade
            finaltradetopop=self.pop(tradeidx)
            assert (len(self)+1) == old_trade_count

        else:
            ## Pop part of the trade, by spawing a child order
            (parent_trade, finaltradetopop)=tradetopop.spawn_child_trade(share=maxtopop)
            
            ## Remove the original trade
            self.pop(tradeidx)
            
            ## Add the residual trade
            self.append(parent_trade)
            
            assert len(self) == old_trade_count

        self.date_sort()

        assert abs(self.final_position()+finaltradetopop.SignQuantity - old_final_position)<THRESHOLD
        
        return finaltradetopop
    def _check_inputs(self):
        if self.Commission<0.0:
            raise Exception("can't have negative commssion")
        if self.Tax<0.0:
            raise Exception("can't have negative tax")
        if self.Quantity<0:
            raise Exception("Quantity can't be negative (you're confusing with SignQuantity")
        if "SignQuantity" in self.argsused:
            if "Quantity" in self.argsused and "BS" in self.argsused:
                checksignquant = self._signed_quantity()
                
                if checksignquant!=self.SignQuantity:
                    raise Exception("Signed quantity of %d not consistent with quantity of %d and BS of %s" % 
                                    (self.SignQuantity, self.Quantity, self.BS))

        if "typestring" in self.argsused:
            assert self.typestring in ["Open", "Close", "OverClose"]

        if "Value" in self.argsused:
            if not self.Value==0.0 and self.SignQuantity==0.0:
                assert not signs_match(self.Value, self.SignQuantity) 
Ejemplo n.º 12
0
    def _check_inputs(self):
        if self.Commission<0.0:
            raise Exception("can't have negative commssion")
        if self.Tax<0.0:
            raise Exception("can't have negative tax")
        if self.Quantity<0:
            raise Exception("Quantity can't be negative (you're confusing with SignQuantity")
        if "SignQuantity" in self.argsused:
            if "Quantity" in self.argsused and "BS" in self.argsused:
                checksignquant = self._signed_quantity()
                
                if checksignquant!=self.SignQuantity:
                    raise Exception("Signed quantity of %d not consistent with quantity of %d and BS of %s" % 
                                    (self.SignQuantity, self.Quantity, self.BS))

        if "typestring" in self.argsused:
            assert self.typestring in ["Open", "Close", "OverClose"]

        if "Value" in self.argsused:
            if not self.Value==0.0 and self.SignQuantity==0.0:
                assert not signs_match(self.Value, self.SignQuantity) 
 def idx_of_last_trade_same_day(self, tradetomatch):
     ## Return indices of trades with same date, executed prior to this trade, with opposite sign
     
     tradedatetime=tradetomatch.Date
     
     self.date_sort()
     
     tradedate=tradedatetime.date()
     
     listdatetimes=[trade.Date for trade in self]
     listdates=[x.date() for x in listdatetimes]
     listsignquant=[trade.SignQuantity for trade in self]
     
     ## done on same day, but not in future
     ## Future trades on same day will be picked up in 'within 30 days' rule
     same_day_trades=[idx for idx in range(len(listdates)) 
                      if listdates[idx]==tradedate and listdatetimes[idx]<tradedatetime
                      and not signs_match(listsignquant[idx], tradetomatch.SignQuantity)]
     
     if len(same_day_trades)==0:
         return None
     
     return same_day_trades[-1]
    def _last_child(self,share=None, pro_rata=None):
        
        oldquantity=self.SignQuantity
    
        if pro_rata is not None:
            assert type(pro_rata) is float 
            assert pro_rata>=0.0 and pro_rata<=1.0

            if abs(pro_rata - 1.0)<THRESHOLD:
                return True
            else:
                return False
        
        if share is not None:
            assert type(share) is float
            assert signs_match(share, oldquantity)
            assert abs(share)<=abs(oldquantity)
            
            if abs(share - oldquantity)<THRESHOLD:
                return True
            else:
                return False
            
        raise Exception("no share or pro rata")
Ejemplo n.º 15
0
    def _last_child(self,share=None, pro_rata=None):
        
        oldquantity=self.SignQuantity
    
        if pro_rata is not None:
            assert type(pro_rata) is float 
            assert pro_rata>=0.0 and pro_rata<=1.0

            if abs(pro_rata - 1.0)<THRESHOLD:
                return True
            else:
                return False
        
        if share is not None:
            assert type(share) is float
            assert signs_match(share, oldquantity)
            assert abs(share)<=abs(oldquantity)
            
            if abs(share - oldquantity)<THRESHOLD:
                return True
            else:
                return False
            
        raise Exception("no share or pro rata")
Ejemplo n.º 16
0
    def _proportionate_pop_idx(self, tradeidxlist, totaltopop):
        """
        Reduce all trades in tradeidxlist by a proportion

        """

        old_final_position = copy(self.final_position())
        old_trade_count = copy(len(self))

        if not all([trade._has_allocation_data() for trade in self]):
            raise Exception(
                "You can't add spawn pseudo trades without _add_cumulative_data first"
            )

        original_trades_to_trim = TradeList(
            [self[idx] for idx in tradeidxlist])

        total_in_list = original_trades_to_trim.final_position()

        assert signs_match(totaltopop, total_in_list)

        pro_rata = totaltopop / total_in_list

        residual = 1.0 - pro_rata

        if abs(residual) < THRESHOLD:
            residual = 0.0
            pro_rata = 1.0

        ## Returns list of tuples (parent, child)
        tradetuplelist = TradeList([
            tradetopop.spawn_child_trade(pro_rata=pro_rata)
            for tradetopop in original_trades_to_trim
        ])

        ## remove original trades
        for trade in original_trades_to_trim:
            ## find matching trade (can't use original indices since will change with size of list)
            trade_idx = [idx for idx in range(len(self)) if self[idx] == trade]
            assert len(trade_idx) == 1

            self.pop(trade_idx[0])

        popped_trades = TradeList(
            [tradetuple[1] for tradetuple in tradetuplelist])
        assert abs(totaltopop - popped_trades.final_position()) < THRESHOLD

        ## Residual left behind...
        if residual > 0.0:
            ## Put residual parent trades back in
            [self.append(tradetuple[0]) for tradetuple in tradetuplelist]

            assert len(self) == old_trade_count

        else:
            ## No residual trades, just pop in their entirity
            ## We've permanently lost these trades
            assert (len(self) + len(popped_trades)) == old_trade_count

        self.date_sort()

        assert abs(self.final_position() + totaltopop -
                   old_final_position) < THRESHOLD

        return popped_trades