def test_combineToZero(self, p: Position) -> None: opposite = Position( instrument=p.instrument, quantity=-p.quantity, costBasis=-p.costBasis ) combined = p + opposite self.assertEqual(combined.quantity, Decimal(0)) self.assertEqual(combined.costBasis, Decimal(0))
def _parseFidelityPosition(p: _FidelityPosition, instrumentFactory: _InstrumentFactory) -> Position: qty = Decimal(p.quantity) return Position( instrument=instrumentFactory(p), quantity=qty, costBasis=Cash(currency=Currency.USD, quantity=Decimal(p.costBasis)), )
def test_combineIncreasesBasis(self, i: Instrument) -> None: a = Position( instrument=i, quantity=Decimal("100"), costBasis=Cash(currency=i.currency, quantity=Decimal("10")), ) b = Position( instrument=i, quantity=Decimal("300"), costBasis=Cash(currency=i.currency, quantity=Decimal("20")), ) combined = a + b self.assertEqual(combined.instrument, i) self.assertEqual(combined.quantity, Decimal("400")) self.assertEqual( combined.costBasis, Cash(currency=i.currency, quantity=Decimal("30")) )
def test_fuzzPosition(self, position: IB.Position) -> None: try: parsedPosition = _extractPosition(position) except ValueError: return self.assertEqual( parsedPosition.quantity, Position.quantizeQuantity(Decimal(position.position)), ) self.validatePositionContract(position, parsedPosition.instrument)
def test_combineIsCommutative( self, i: Instrument, aQty: Decimal, aPrice: Decimal, bQty: Decimal, bPrice: Decimal, ) -> None: assume(aQty != -bQty) a = Position( instrument=i, quantity=aQty, costBasis=Cash(currency=i.currency, quantity=aPrice), ) b = Position( instrument=i, quantity=bQty, costBasis=Cash(currency=i.currency, quantity=bPrice), ) self.assertEqual(a + b, b + a)
def _parseVanguardPosition(p: _VanguardPosition, activity: List[Activity]) -> Position: instrument: Instrument if len(p.symbol) > 0: instrument = Stock(p.symbol, currency=Currency.USD) else: instrument = _guessInstrumentForInvestmentName(p.investmentName) qty = Decimal(p.shares) realizedBasis = _realizedBasisForSymbol(instrument.symbol, activity) assert realizedBasis, "Invalid realizedBasis: %s for %s" % ( realizedBasis, instrument, ) return Position(instrument=instrument, quantity=qty, costBasis=realizedBasis)
def _parseSchwabPosition(p: _SchwabPosition) -> Optional[Position]: if re.match(r"Futures |Cash & Money Market|Account Total", p.symbol): return None instrument: Instrument if re.match(r"Equity|ETFs", p.securityType): instrument = Stock(p.symbol, currency=Currency.USD) elif re.match(r"Option", p.securityType): instrument = _parseOption(p.symbol) elif re.match(r"Fixed Income", p.securityType): instrument = Bond(p.symbol, currency=Currency.USD) else: raise ValueError(f"Unrecognized security type: {p.securityType}") return Position( instrument=instrument, quantity=_schwabDecimal(p.quantity), costBasis=Cash(currency=Currency.USD, quantity=_schwabDecimal(p.costBasis)), )
def _extractPosition(p: IB.Position) -> Position: tag = p.contract.secType symbol = p.contract.localSymbol if p.contract.currency not in Currency.__members__: raise ValueError(f"Unrecognized currency in position: {p}") currency = Currency[p.contract.currency] exchange = p.contract.exchange or None try: instrument: Instrument if tag == "STK": instrument = Stock(symbol=symbol, currency=currency, exchange=exchange) elif tag == "BILL" or tag == "BOND": instrument = Bond( symbol=symbol, currency=currency, validateSymbol=False, exchange=exchange, ) elif tag == "OPT": instrument = _parseOption( symbol=symbol, currency=currency, multiplier=_parseFiniteDecimal(p.contract.multiplier), exchange=exchange, ) elif tag == "FUT": instrument = Future( symbol=symbol, currency=currency, multiplier=_parseFiniteDecimal(p.contract.multiplier), expiration=_parseIBDate( p.contract.lastTradeDateOrContractMonth).date(), exchange=exchange, ) elif tag == "FOP": instrument = _parseFutureOptionContract(p.contract, currency=currency, exchange=exchange) elif tag == "CASH": instrument = _parseForex(symbol=symbol, currency=currency, exchange=exchange) else: raise ValueError( f"Unrecognized/unsupported security type in position: {p}") qty = _parseFiniteDecimal(p.position) costBasis = _parseFiniteDecimal(p.avgCost) * qty return Position( instrument=instrument, quantity=qty, costBasis=Cash(currency=Currency[p.contract.currency], quantity=costBasis), ) except InvalidOperation: raise ValueError( f"One of the numeric position or contract values is out of range: {p}" )