Example #1
0
 def __init__(self, tranlist):
     # Initialize with *TRANLIST Element
     dtstart, dtend = tranlist[0:2]
     tranlist = tranlist[2:]
     self.dtstart = DateTime().convert(dtstart.text)
     self.dtend = DateTime().convert(dtend.text)
     self.extend([Aggregate.from_etree(tran) for tran in tranlist])
Example #2
0
 def __init__(self, tranlist):
     # Initialize with *TRANLIST Element
     dtstart, dtend = tranlist[0:2]
     tranlist = tranlist[2:]
     self.dtstart = DateTime.convert(dtstart.text)
     self.dtend = DateTime.convert(dtend.text)
     self.extend([Aggregate.from_etree(tran) for tran in tranlist])
Example #3
0
class SONRS(FI, STATUS):
    dtserver = DateTime(required=True)
    userkey = String(64)
    tskeyexpire = DateTime()
    language = OneOf(*LANG_CODES)
    dtprofup = DateTime()
    dtacctup = DateTime()
    sesscookie = String(1000)
    accesskey = String(1000)
Example #4
0
 def inctran(self, inctran, dtstart, dtend):
     """ """
     tran = ET.Element('INCTRAN')
     if dtstart:
         ET.SubElement(tran, 'DTSTART').text = DateTime().unconvert(dtstart)
     if dtend:
         ET.SubElement(tran, 'DTEND').text = DateTime().unconvert(dtend)
     ET.SubElement(tran, 'INCLUDE').text = Bool().unconvert(inctran)
     return tran
Example #5
0
class DEBTINFO(SECINFO):
    parvalue = Decimal(required=True)
    debttype = OneOf('COUPON', 'ZERO', required=True)
    debtclass = OneOf('TREASURY', 'MUNICIPAL', 'CORPORATE', 'OTHER')
    couponrt = Decimal(4)
    dtcoupon = DateTime()
    couponfreq = OneOf('MONTHLY', 'QUARTERLY', 'SEMIANNUAL', 'ANNUAL', 'OTHER')
    callprice = Decimal(4)
    yieldtocall = Decimal(4)
    dtcall = DateTime()
    calltype = OneOf('CALL', 'PUT', 'PREFUND', 'MATURITY')
    ytmat = Decimal(4)
    dtmat = DateTime()
    assetclass = OneOf(*ASSETCLASSES)
    fiassetclass = String(32)
Example #6
0
class STOCKINFO(SECINFO):
    stocktype = OneOf('COMMON', 'PREFERRED', 'CONVERTIBLE', 'OTHER')
    yld = Decimal(4)
    dtyieldasof = DateTime()
    typedesc = String(32)
    assetclass = OneOf(*ASSETCLASSES)
    fiassetclass = String(32)
Example #7
0
class OPTINFO(SECINFO):
    opttype = OneOf('CALL', 'PUT', required=True)
    strikeprice = Decimal(required=True)
    dtexpire = DateTime(required=True)
    shperctrct = Integer(required=True)
    assetclass = OneOf(*ASSETCLASSES)
    fiassetclass = String(32)

    def __init__(self, elem):
        """
        Strip SECID of underlying so it doesn't overwrite SECID of option
        during _flatten()
        """
        # Do all XPath searches before removing nodes from the tree
        #   which seems to mess up the DOM in Python3 and throw an
        #   AttributeError on subsequent searches.
        secid = elem.find('./SECID')

        if secid is not None:
            # A <SECID> aggregate referring to the security underlying the
            # option is, in general, *not* going to be contained in <SECLIST>
            # (because you don't necessarily have a position in the underlying).
            # Since the <SECID> for the underlying only gives us fields for
            # (uniqueidtype, uniqueid) we can't really go ahead and use this
            # information to create a corresponding SECINFO instance (since we
            # lack information about the security subclass).  It's unclear that
            # the SECID of the underlying is really needed for anything, so we
            # disregard it.
            elem.remove(secid)

        super(OPTINFO, self).__init__(elem)
Example #8
0
class OPTINFO(SECINFO):
    opttype = OneOf('CALL', 'PUT', required=True)
    strikeprice = Decimal(required=True)
    dtexpire = DateTime(required=True)
    shperctrct = Integer(required=True)
    assetclass = OneOf(*ASSETCLASSES)
    fiassetclass = String(32)
Example #9
0
class STOCKINFO(SECINFO):
    stocktype = OneOf('COMMON', 'PREFERRED', 'CONVERTIBLE', 'OTHER')
    yld = Decimal(4)
    dtyieldasof = DateTime()
    typedesc = String(32)
    assetclass = OneOf(*ASSETCLASSES)
    fiassetclass = String(32)

    def __init__(self, elem):
        """
        Rename 'yield' (Python reserved word) to 'yld'
        """
        extra_attrs = {}

        # Do all XPath searches before removing nodes from the tree
        #   which seems to mess up the DOM in Python3 and throw an
        #   AttributeError on subsequent searches.
        yld = elem.find('./YIELD')

        if yld is not None:
            # Rename; save for later
            extra_attrs['yld'] = yld.text
            elem.remove(yld)

        super(STOCKINFO, self).__init__(elem)

        # Add back data previously stripped/mangled
        for attr, val in extra_attrs.items():
            setattr(self, attr, val)
Example #10
0
class INVPOS(SECID, CURRENCY):
    heldinacct = OneOf(*INVSUBACCTS, required=True)
    postype = OneOf('SHORT', 'LONG', required=True)
    units = Decimal(required=True)
    unitprice = Decimal(4, required=True)
    mktval = Decimal(required=True)
    dtpriceasof = DateTime(required=True)
    memo = String(255)
    inv401ksource = OneOf(*INV401KSOURCES)
Example #11
0
class TRANSFER(INVTRAN, SECID):
    subacctsec = OneOf(*INVSUBACCTS, required=True)
    units = Decimal(required=True)
    tferaction = OneOf('IN', 'OUT', required=True)
    postype = OneOf('SHORT', 'LONG', required=True)
    avgcostbasis = Decimal()
    unitprice = Decimal()
    dtpurchase = DateTime()
    inv401ksource = OneOf(*INV401KSOURCES)
Example #12
0
class SECINFO(CURRENCY, SECID):
    # FIs abuse SECNAME/TICKER
    # Relaxing the length constraints from the OFX spec does little harm
    #secname = String(120, required=True)
    #ticker = String(32)
    secname = String(255, required=True)
    ticker = String(255)
    fiid = String(32)
    rating = String(10)
    unitprice = Decimal()
    dtasof = DateTime()
    memo = String(255)
Example #13
0
 def profile_request(self, user=None, password=None):
     """ """
     user = user or 'elmerfudd'
     password = password or 'TOPSECRET'
     ofx = ET.Element('OFX')
     ofx.append(self.signon(user, password))
     msgsrq = ET.SubElement(ofx, 'PROFMSGSRQV1')
     profrq = ET.Element('PROFRQ')
     ET.SubElement(profrq, 'CLIENTROUTING').text = 'NONE'
     ET.SubElement(profrq, 'DTPROFUP').text = DateTime().unconvert(
         datetime.date(1990, 1, 1))
     msgsrq.append(self._wraptrn(profrq))
     return ofx
Example #14
0
class STMTTRN(TRAN, ORIGCURRENCY):
    trntype = OneOf('CREDIT',
                    'DEBIT',
                    'INT',
                    'DIV',
                    'FEE',
                    'SRVCHG',
                    'DEP',
                    'ATM',
                    'POS',
                    'XFER',
                    'CHECK',
                    'PAYMENT',
                    'CASH',
                    'DIRECTDEP',
                    'DIRECTDEBIT',
                    'REPEATPMT',
                    'OTHER',
                    required=True)
    dtposted = DateTime(required=True)
    dtuser = DateTime()
    dtavail = DateTime()
    trnamt = Decimal(required=True)
    correctfitid = Decimal()
    correctaction = OneOf('REPLACE', 'DELETE')
    checknum = String(12)
    refnum = String(32)
    sic = Integer()
    payeeid = String(12)
    name = String(32)
    memo = String(255)
    inv401ksource = OneOf(*INV401KSOURCES)

    payee = None
    bankacctto = None
    ccacctto = None
Example #15
0
 def signon(self, user, password):
     msgsrq = ET.Element('SIGNONMSGSRQV1')
     sonrq = ET.SubElement(msgsrq, 'SONRQ')
     ET.SubElement(sonrq, 'DTCLIENT').text = DateTime().unconvert(
         datetime.datetime.now())
     ET.SubElement(sonrq, 'USERID').text = user
     ET.SubElement(sonrq, 'USERPASS').text = password
     ET.SubElement(sonrq, 'LANGUAGE').text = 'ENG'
     if self.org:
         fi = ET.SubElement(sonrq, 'FI')
         ET.SubElement(fi, 'ORG').text = self.org
         if self.fid:
             ET.SubElement(fi, 'FID').text = self.fid
     ET.SubElement(sonrq, 'APPID').text = self.appid
     ET.SubElement(sonrq, 'APPVER').text = str(self.appver)
     return msgsrq
Example #16
0
class INVBUY(INVTRAN, SECID, ORIGCURRENCY):
    units = Decimal(required=True)
    unitprice = Decimal(4, required=True)
    markup = Decimal()
    commission = Decimal()
    taxes = Decimal()
    fees = Decimal()
    load = Decimal()
    total = Decimal(required=True)
    subacctsec = OneOf(*INVSUBACCTS, required=True)
    subacctfund = OneOf(*INVSUBACCTS, required=True)
    loanid = String(32)
    loanprincipal = Decimal()
    loaninterest = Decimal()
    inv401ksource = OneOf(*INV401KSOURCES)
    dtpayroll = DateTime()
    prioryearcontrib = Bool()
Example #17
0
def do_stmt(args):
    client = OFXClient(args.url,
                       args.org,
                       args.fid,
                       version=args.version,
                       appid=args.appid,
                       appver=args.appver)

    # Define accounts
    accts = []
    for accttype in ('checking', 'savings', 'moneymrkt', 'creditline'):
        for acctid in getattr(args, accttype):
            a = BankAcct(args.bankid, acctid, accttype)
            accts.append(a)

    for acctid in args.creditcard:
        accts.append(CcAcct(acctid))

    for acctid in args.investment:
        accts.append(InvAcct(args.brokerid, acctid))

    # Use dummy password for dummy request
    if args.dry_run:
        password = '******'
    else:
        password = getpass()

    # Statement parameters
    d = vars(args)
    # convert dtstart/dtend/dtasof from str to datetime
    kwargs = {
        k: DateTime().convert(v)
        for k, v in d.items() if k.startswith('dt')
    }
    # inctrans/incpos/incbal
    kwargs.update({k: v for k, v in d.items() if k.startswith('inc')})

    request = client.statement_request(args.user, password, accts, **kwargs)

    # Handle request
    if args.dry_run:
        print(client.ofxheader + ET.tostring(request).decode())
    else:
        response = client.download(request)
        print(response.read())
Example #18
0
class MFINFO(SECINFO):
    mftype = OneOf('OPENEND', 'CLOSEEND', 'OTHER')
    yld = Decimal(4)
    dtyieldasof = DateTime()

    mfassetclass = []
    fimfassetclass = []

    def __init__(self, elem):
        """
        Strip MFASSETCLASS/FIMFASSETCLASS - lists that will blow up _flatten()
        Rename 'yield' (Python reserved word) to 'yld'
        """
        extra_attrs = {}

        # Do all XPath searches before removing nodes from the tree
        #   which seems to mess up the DOM in Python3 and throw an
        #   AttributeError on subsequent searches.
        mfassetclass = elem.find('./MFASSETCLASS')
        fimfassetclass = elem.find('./FIMFASSETCLASS')
        yld = elem.find('./YIELD')

        if mfassetclass is not None:
            # Convert PORTIONs; save for later
            extra_attrs['mfassetclass'] = [
                Aggregate.from_etree(p) for p in mfassetclass
            ]
            elem.remove(mfassetclass)
        if fimfassetclass is not None:
            # Convert FIPORTIONs; save for later
            extra_attrs['fimfassetclass'] = [
                Aggregate.from_etree(p) for p in fimfassetclass
            ]
            elem.remove(fimfassetclass)
        if yld is not None:
            # Rename; save for later
            extra_attrs['yld'] = yld.text
            elem.remove(yld)

        super(MFINFO, self).__init__(elem)

        # Add back data previously stripped/mangled
        for attr, val in extra_attrs.items():
            setattr(self, attr, val)
Example #19
0
    def _init(self, invstmtrs):
        dtasof = invstmtrs.find('DTASOF').text
        self.datetime = DateTime().convert(dtasof)

        # INVTRANLIST
        tranlist = invstmtrs.find('INVTRANLIST')
        if tranlist is not None:
            self.transactions = INVTRANLIST(tranlist)
        else:
            self.transactions = []

        # INVPOSLIST
        poslist = invstmtrs.find('INVPOSLIST')
        if poslist is not None:
            self.positions = [Aggregate.from_etree(pos) for pos in poslist]
        else:
            self.positions = []

        # INVBAL
        invbal = invstmtrs.find('INVBAL')
        if invbal is not None:
            # First strip off BALLIST & process it
            ballist = invbal.find('BALLIST')
            if ballist is not None:
                invbal.remove(ballist)
                self.other_balances = [
                    Aggregate.from_etree(bal) for bal in ballist
                ]
            else:
                self.other_balances = []
            # Now we can flatten the rest of INVBAL
            self.balances = Aggregate.from_etree(invbal)
        else:
            self.balances = []
            self.other_balances = []

        # Unsupported subaggregates
        for tag in ('INVOOLIST', 'INV401K', 'INV401KBAL', 'MKTGINFO'):
            child = invstmtrs.find(tag)
            if child is not None:
                invstmtrs.remove
Example #20
0
    def _init(self, invstmtrs):
        dtasof = invstmtrs.find('DTASOF').text
        self.datetime = DateTime.convert(dtasof)

        # INVTRANLIST
        tranlist = invstmtrs.find('INVTRANLIST')
        if tranlist is not None:
            self.transactions = INVTRANLIST(tranlist)
        else:
            self.transactions = []

        # INVPOSLIST
        poslist = invstmtrs.find('INVPOSLIST')
        if poslist is not None:
            self.positions = [Aggregate.from_etree(pos) for pos in poslist]
        else:
            self.positions = []

        # INVBAL
        invbal = invstmtrs.find('INVBAL')
        if invbal is not None:
            # First strip off BALLIST & process it
            ballist = invbal.find('BALLIST')
            if ballist is not None:
                invbal.remove(ballist)
                self.other_balances = [Aggregate.from_etree(bal) for bal in ballist]
            else:
                self.other_balances = []
            # Now we can flatten the rest of INVBAL
            self.balances = Aggregate.from_etree(invbal)
        else:
            self.balances = []
            self.other_balances = []

        # Unsupported subaggregates
        for tag in ('INVOOLIST', 'INV401K', 'INV401KBAL', 'MKTGINFO'):
            child = invstmtrs.find(tag)
            if child is not None:
                invstmtrs.remove
Example #21
0
class MFINFO(SECINFO):
    mftype = OneOf('OPENEND', 'CLOSEEND', 'OTHER')
    yld = Decimal(4)
    dtyieldasof = DateTime()

    mfassetclass = []
    fimfassetclass = []

    def __init__(self, elem, strict=True):
        """ 
        Strip MFASSETCLASS/FIMFASSETCLASS - lists that will blow up _flatten()
        """
        extra_attrs = {}

        # Do all XPath searches before removing nodes from the tree
        #   which seems to mess up the DOM in Python3 and throw an
        #   AttributeError on subsequent searches.
        mfassetclass = elem.find('./MFASSETCLASS')
        fimfassetclass = elem.find('./FIMFASSETCLASS')

        if mfassetclass is not None:
            # Convert PORTIONs; save for later
            extra_attrs['mfassetclass'] = [
                Aggregate.from_etree(p) for p in mfassetclass
            ]
            elem.remove(mfassetclass)
        if fimfassetclass is not None:
            # Convert FIPORTIONs; save for later
            extra_attrs['fimfassetclass'] = [
                Aggregate.from_etree(p) for p in fimfassetclass
            ]
            elem.remove(fimfassetclass)

        super(MFINFO, self).__init__(elem, strict=strict)

        # Staple MFASSETCLASS/FIMFASSETCLASS onto MFINFO
        for attr, val in extra_attrs.items():
            setattr(self, attr, val)
Example #22
0
class AVAILBAL(Aggregate):
    balamt = Decimal(required=True)
    dtasof = DateTime(required=True)
Example #23
0
class BAL(CURRENCY):
    name = String(32, required=True)
    desc = String(80, required=True)
    baltype = OneOf('DOLLAR', 'PERCENT', 'NUMBER', required=True)
    value = Decimal(required=True)
    dtasof = DateTime()
Example #24
0
class INVTRAN(TRAN):
    dttrade = DateTime(required=True)
    dtsettle = DateTime()
    reversalfitid = String(255)
    memo = String(255)
Example #25
0
 def incpos(self, dtasof, incpos):
     pos = ET.Element('INCPOS')
     if dtasof:
         ET.SubElement(pos, 'DTASOF').text = DateTime().unconvert(dtasof)
     ET.SubElement(pos, 'INCLUDE').text = Bool().unconvert(incpos)
     return pos