| #!/usr/bin/python |
| # |
| # Copyright (C) 2009 Tan Swee Heng |
| # |
| # Licensed under the Apache License, Version 2.0 (the "License"); |
| # you may not use this file except in compliance with the License. |
| # You may obtain a copy of the License at |
| # |
| # http://www.apache.org/licenses/LICENSE-2.0 |
| # |
| # Unless required by applicable law or agreed to in writing, software |
| # distributed under the License is distributed on an "AS IS" BASIS, |
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| # See the License for the specific language governing permissions and |
| # limitations under the License. |
| |
| |
| """Contains extensions to Atom objects used with Google Finance.""" |
| |
| |
| __author__ = 'thesweeheng@gmail.com' |
| |
| |
| import atom |
| import gdata |
| |
| |
| GD_NAMESPACE = 'http://schemas.google.com/g/2005' |
| GF_NAMESPACE = 'http://schemas.google.com/finance/2007' |
| |
| |
| class Money(atom.AtomBase): |
| """The <gd:money> element.""" |
| _tag = 'money' |
| _namespace = GD_NAMESPACE |
| _attributes = atom.AtomBase._attributes.copy() |
| _attributes['amount'] = 'amount' |
| _attributes['currencyCode'] = 'currency_code' |
| |
| def __init__(self, amount=None, currency_code=None, **kwargs): |
| self.amount = amount |
| self.currency_code = currency_code |
| atom.AtomBase.__init__(self, **kwargs) |
| |
| def __str__(self): |
| return "%s %s" % (self.amount, self.currency_code) |
| |
| |
| def MoneyFromString(xml_string): |
| return atom.CreateClassFromXMLString(Money, xml_string) |
| |
| |
| class _Monies(atom.AtomBase): |
| """An element containing multiple <gd:money> in multiple currencies.""" |
| _namespace = GF_NAMESPACE |
| _children = atom.AtomBase._children.copy() |
| _children['{%s}money' % GD_NAMESPACE] = ('money', [Money]) |
| |
| def __init__(self, money=None, **kwargs): |
| self.money = money or [] |
| atom.AtomBase.__init__(self, **kwargs) |
| |
| def __str__(self): |
| return " / ".join(["%s" % i for i in self.money]) |
| |
| |
| class CostBasis(_Monies): |
| """The <gf:costBasis> element.""" |
| _tag = 'costBasis' |
| |
| |
| def CostBasisFromString(xml_string): |
| return atom.CreateClassFromXMLString(CostBasis, xml_string) |
| |
| |
| class DaysGain(_Monies): |
| """The <gf:daysGain> element.""" |
| _tag = 'daysGain' |
| |
| |
| def DaysGainFromString(xml_string): |
| return atom.CreateClassFromXMLString(DaysGain, xml_string) |
| |
| |
| class Gain(_Monies): |
| """The <gf:gain> element.""" |
| _tag = 'gain' |
| |
| |
| def GainFromString(xml_string): |
| return atom.CreateClassFromXMLString(Gain, xml_string) |
| |
| |
| class MarketValue(_Monies): |
| """The <gf:marketValue> element.""" |
| _tag = 'gain' |
| _tag = 'marketValue' |
| |
| |
| def MarketValueFromString(xml_string): |
| return atom.CreateClassFromXMLString(MarketValue, xml_string) |
| |
| |
| class Commission(_Monies): |
| """The <gf:commission> element.""" |
| _tag = 'commission' |
| |
| |
| def CommissionFromString(xml_string): |
| return atom.CreateClassFromXMLString(Commission, xml_string) |
| |
| |
| class Price(_Monies): |
| """The <gf:price> element.""" |
| _tag = 'price' |
| |
| |
| def PriceFromString(xml_string): |
| return atom.CreateClassFromXMLString(Price, xml_string) |
| |
| |
| class Symbol(atom.AtomBase): |
| """The <gf:symbol> element.""" |
| _tag = 'symbol' |
| _namespace = GF_NAMESPACE |
| _attributes = atom.AtomBase._attributes.copy() |
| _attributes['fullName'] = 'full_name' |
| _attributes['exchange'] = 'exchange' |
| _attributes['symbol'] = 'symbol' |
| |
| def __init__(self, full_name=None, exchange=None, symbol=None, **kwargs): |
| self.full_name = full_name |
| self.exchange = exchange |
| self.symbol = symbol |
| atom.AtomBase.__init__(self, **kwargs) |
| |
| def __str__(self): |
| return "%s:%s (%s)" % (self.exchange, self.symbol, self.full_name) |
| |
| |
| def SymbolFromString(xml_string): |
| return atom.CreateClassFromXMLString(Symbol, xml_string) |
| |
| |
| class TransactionData(atom.AtomBase): |
| """The <gf:transactionData> element.""" |
| _tag = 'transactionData' |
| _namespace = GF_NAMESPACE |
| _attributes = atom.AtomBase._attributes.copy() |
| _attributes['type'] = 'type' |
| _attributes['date'] = 'date' |
| _attributes['shares'] = 'shares' |
| _attributes['notes'] = 'notes' |
| _children = atom.AtomBase._children.copy() |
| _children['{%s}commission' % GF_NAMESPACE] = ('commission', Commission) |
| _children['{%s}price' % GF_NAMESPACE] = ('price', Price) |
| |
| def __init__(self, type=None, date=None, shares=None, |
| notes=None, commission=None, price=None, **kwargs): |
| self.type = type |
| self.date = date |
| self.shares = shares |
| self.notes = notes |
| self.commission = commission |
| self.price = price |
| atom.AtomBase.__init__(self, **kwargs) |
| |
| |
| def TransactionDataFromString(xml_string): |
| return atom.CreateClassFromXMLString(TransactionData, xml_string) |
| |
| |
| class TransactionEntry(gdata.GDataEntry): |
| """An entry of the transaction feed. |
| |
| A TransactionEntry contains TransactionData such as the transaction |
| type (Buy, Sell, Sell Short, or Buy to Cover), the number of units, |
| the date, the price, any commission, and any notes. |
| """ |
| _tag = 'entry' |
| _namespace = atom.ATOM_NAMESPACE |
| _children = gdata.GDataEntry._children.copy() |
| _children['{%s}transactionData' % GF_NAMESPACE] = ( |
| 'transaction_data', TransactionData) |
| |
| def __init__(self, transaction_data=None, **kwargs): |
| self.transaction_data = transaction_data |
| gdata.GDataEntry.__init__(self, **kwargs) |
| |
| def transaction_id(self): |
| return self.id.text.split("/")[-1] |
| |
| transaction_id = property(transaction_id, doc='The transaction ID.') |
| |
| |
| def TransactionEntryFromString(xml_string): |
| return atom.CreateClassFromXMLString(TransactionEntry, xml_string) |
| |
| |
| class TransactionFeed(gdata.GDataFeed): |
| """A feed that lists all of the transactions that have been recorded for |
| a particular position. |
| |
| A transaction is a collection of information about an instance of |
| buying or selling a particular security. The TransactionFeed lists all |
| of the transactions that have been recorded for a particular position |
| as a list of TransactionEntries. |
| """ |
| _tag = 'feed' |
| _namespace = atom.ATOM_NAMESPACE |
| _children = gdata.GDataFeed._children.copy() |
| _children['{%s}entry' % atom.ATOM_NAMESPACE] = ('entry', [TransactionEntry]) |
| |
| |
| def TransactionFeedFromString(xml_string): |
| return atom.CreateClassFromXMLString(TransactionFeed, xml_string) |
| |
| |
| class TransactionFeedLink(atom.AtomBase): |
| """Link to TransactionFeed embedded in PositionEntry. |
| |
| If a PositionFeed is queried with transactions='true', TransactionFeeds |
| are inlined in the returned PositionEntries. These TransactionFeeds are |
| accessible via TransactionFeedLink's feed attribute. |
| """ |
| _tag = 'feedLink' |
| _namespace = GD_NAMESPACE |
| _attributes = atom.AtomBase._attributes.copy() |
| _attributes['href'] = 'href' |
| _children = atom.AtomBase._children.copy() |
| _children['{%s}feed' % atom.ATOM_NAMESPACE] = ( |
| 'feed', TransactionFeed) |
| |
| def __init__(self, href=None, feed=None, **kwargs): |
| self.href = href |
| self.feed = feed |
| atom.AtomBase.__init__(self, **kwargs) |
| |
| |
| class PositionData(atom.AtomBase): |
| """The <gf:positionData> element.""" |
| _tag = 'positionData' |
| _namespace = GF_NAMESPACE |
| _attributes = atom.AtomBase._attributes.copy() |
| _attributes['gainPercentage'] = 'gain_percentage' |
| _attributes['return1w'] = 'return1w' |
| _attributes['return4w'] = 'return4w' |
| _attributes['return3m'] = 'return3m' |
| _attributes['returnYTD'] = 'returnYTD' |
| _attributes['return1y'] = 'return1y' |
| _attributes['return3y'] = 'return3y' |
| _attributes['return5y'] = 'return5y' |
| _attributes['returnOverall'] = 'return_overall' |
| _attributes['shares'] = 'shares' |
| _children = atom.AtomBase._children.copy() |
| _children['{%s}costBasis' % GF_NAMESPACE] = ('cost_basis', CostBasis) |
| _children['{%s}daysGain' % GF_NAMESPACE] = ('days_gain', DaysGain) |
| _children['{%s}gain' % GF_NAMESPACE] = ('gain', Gain) |
| _children['{%s}marketValue' % GF_NAMESPACE] = ('market_value', MarketValue) |
| |
| def __init__(self, gain_percentage=None, |
| return1w=None, return4w=None, return3m=None, returnYTD=None, |
| return1y=None, return3y=None, return5y=None, return_overall=None, |
| shares=None, cost_basis=None, days_gain=None, |
| gain=None, market_value=None, **kwargs): |
| self.gain_percentage = gain_percentage |
| self.return1w = return1w |
| self.return4w = return4w |
| self.return3m = return3m |
| self.returnYTD = returnYTD |
| self.return1y = return1y |
| self.return3y = return3y |
| self.return5y = return5y |
| self.return_overall = return_overall |
| self.shares = shares |
| self.cost_basis = cost_basis |
| self.days_gain = days_gain |
| self.gain = gain |
| self.market_value = market_value |
| atom.AtomBase.__init__(self, **kwargs) |
| |
| |
| def PositionDataFromString(xml_string): |
| return atom.CreateClassFromXMLString(PositionData, xml_string) |
| |
| |
| class PositionEntry(gdata.GDataEntry): |
| """An entry of the position feed. |
| |
| A PositionEntry contains the ticker exchange and Symbol for a stock, |
| mutual fund, or other security, along with PositionData such as the |
| number of units of that security that the user holds, and performance |
| statistics. |
| """ |
| _tag = 'entry' |
| _namespace = atom.ATOM_NAMESPACE |
| _children = gdata.GDataEntry._children.copy() |
| _children['{%s}positionData' % GF_NAMESPACE] = ( |
| 'position_data', PositionData) |
| _children['{%s}symbol' % GF_NAMESPACE] = ('symbol', Symbol) |
| _children['{%s}feedLink' % GD_NAMESPACE] = ( |
| 'feed_link', TransactionFeedLink) |
| |
| def __init__(self, position_data=None, symbol=None, feed_link=None, |
| **kwargs): |
| self.position_data = position_data |
| self.symbol = symbol |
| self.feed_link = feed_link |
| gdata.GDataEntry.__init__(self, **kwargs) |
| |
| def position_title(self): |
| return self.title.text |
| |
| position_title = property(position_title, |
| doc='The position title as a string (i.e. position.title.text).') |
| |
| def ticker_id(self): |
| return self.id.text.split("/")[-1] |
| |
| ticker_id = property(ticker_id, doc='The position TICKER ID.') |
| |
| def transactions(self): |
| if self.feed_link.feed: |
| return self.feed_link.feed.entry |
| else: |
| return None |
| |
| transactions = property(transactions, doc=""" |
| Inlined TransactionEntries are returned if PositionFeed is queried |
| with transactions='true'.""") |
| |
| |
| def PositionEntryFromString(xml_string): |
| return atom.CreateClassFromXMLString(PositionEntry, xml_string) |
| |
| |
| class PositionFeed(gdata.GDataFeed): |
| """A feed that lists all of the positions in a particular portfolio. |
| |
| A position is a collection of information about a security that the |
| user holds. The PositionFeed lists all of the positions in a particular |
| portfolio as a list of PositionEntries. |
| """ |
| _tag = 'feed' |
| _namespace = atom.ATOM_NAMESPACE |
| _children = gdata.GDataFeed._children.copy() |
| _children['{%s}entry' % atom.ATOM_NAMESPACE] = ('entry', [PositionEntry]) |
| |
| |
| def PositionFeedFromString(xml_string): |
| return atom.CreateClassFromXMLString(PositionFeed, xml_string) |
| |
| |
| class PositionFeedLink(atom.AtomBase): |
| """Link to PositionFeed embedded in PortfolioEntry. |
| |
| If a PortfolioFeed is queried with positions='true', the PositionFeeds |
| are inlined in the returned PortfolioEntries. These PositionFeeds are |
| accessible via PositionFeedLink's feed attribute. |
| """ |
| _tag = 'feedLink' |
| _namespace = GD_NAMESPACE |
| _attributes = atom.AtomBase._attributes.copy() |
| _attributes['href'] = 'href' |
| _children = atom.AtomBase._children.copy() |
| _children['{%s}feed' % atom.ATOM_NAMESPACE] = ( |
| 'feed', PositionFeed) |
| |
| def __init__(self, href=None, feed=None, **kwargs): |
| self.href = href |
| self.feed = feed |
| atom.AtomBase.__init__(self, **kwargs) |
| |
| |
| class PortfolioData(atom.AtomBase): |
| """The <gf:portfolioData> element.""" |
| _tag = 'portfolioData' |
| _namespace = GF_NAMESPACE |
| _attributes = atom.AtomBase._attributes.copy() |
| _attributes['currencyCode'] = 'currency_code' |
| _attributes['gainPercentage'] = 'gain_percentage' |
| _attributes['return1w'] = 'return1w' |
| _attributes['return4w'] = 'return4w' |
| _attributes['return3m'] = 'return3m' |
| _attributes['returnYTD'] = 'returnYTD' |
| _attributes['return1y'] = 'return1y' |
| _attributes['return3y'] = 'return3y' |
| _attributes['return5y'] = 'return5y' |
| _attributes['returnOverall'] = 'return_overall' |
| _children = atom.AtomBase._children.copy() |
| _children['{%s}costBasis' % GF_NAMESPACE] = ('cost_basis', CostBasis) |
| _children['{%s}daysGain' % GF_NAMESPACE] = ('days_gain', DaysGain) |
| _children['{%s}gain' % GF_NAMESPACE] = ('gain', Gain) |
| _children['{%s}marketValue' % GF_NAMESPACE] = ('market_value', MarketValue) |
| |
| def __init__(self, currency_code=None, gain_percentage=None, |
| return1w=None, return4w=None, return3m=None, returnYTD=None, |
| return1y=None, return3y=None, return5y=None, return_overall=None, |
| cost_basis=None, days_gain=None, gain=None, market_value=None, **kwargs): |
| self.currency_code = currency_code |
| self.gain_percentage = gain_percentage |
| self.return1w = return1w |
| self.return4w = return4w |
| self.return3m = return3m |
| self.returnYTD = returnYTD |
| self.return1y = return1y |
| self.return3y = return3y |
| self.return5y = return5y |
| self.return_overall = return_overall |
| self.cost_basis = cost_basis |
| self.days_gain = days_gain |
| self.gain = gain |
| self.market_value = market_value |
| atom.AtomBase.__init__(self, **kwargs) |
| |
| |
| def PortfolioDataFromString(xml_string): |
| return atom.CreateClassFromXMLString(PortfolioData, xml_string) |
| |
| |
| class PortfolioEntry(gdata.GDataEntry): |
| """An entry of the PortfolioFeed. |
| |
| A PortfolioEntry contains the portfolio's title along with PortfolioData |
| such as currency, total market value, and overall performance statistics. |
| """ |
| _tag = 'entry' |
| _namespace = atom.ATOM_NAMESPACE |
| _children = gdata.GDataEntry._children.copy() |
| _children['{%s}portfolioData' % GF_NAMESPACE] = ( |
| 'portfolio_data', PortfolioData) |
| _children['{%s}feedLink' % GD_NAMESPACE] = ( |
| 'feed_link', PositionFeedLink) |
| |
| def __init__(self, portfolio_data=None, feed_link=None, **kwargs): |
| self.portfolio_data = portfolio_data |
| self.feed_link = feed_link |
| gdata.GDataEntry.__init__(self, **kwargs) |
| |
| def portfolio_title(self): |
| return self.title.text |
| |
| def set_portfolio_title(self, portfolio_title): |
| self.title = atom.Title(text=portfolio_title, title_type='text') |
| |
| portfolio_title = property(portfolio_title, set_portfolio_title, |
| doc='The portfolio title as a string (i.e. portfolio.title.text).') |
| |
| def portfolio_id(self): |
| return self.id.text.split("/")[-1] |
| |
| portfolio_id = property(portfolio_id, |
| doc='The portfolio ID. Do not confuse with portfolio.id.') |
| |
| def positions(self): |
| if self.feed_link.feed: |
| return self.feed_link.feed.entry |
| else: |
| return None |
| |
| positions = property(positions, doc=""" |
| Inlined PositionEntries are returned if PortfolioFeed was queried |
| with positions='true'.""") |
| |
| |
| def PortfolioEntryFromString(xml_string): |
| return atom.CreateClassFromXMLString(PortfolioEntry, xml_string) |
| |
| |
| class PortfolioFeed(gdata.GDataFeed): |
| """A feed that lists all of the user's portfolios. |
| |
| A portfolio is a collection of positions that the user holds in various |
| securities, plus metadata. The PortfolioFeed lists all of the user's |
| portfolios as a list of PortfolioEntries. |
| """ |
| _tag = 'feed' |
| _namespace = atom.ATOM_NAMESPACE |
| _children = gdata.GDataFeed._children.copy() |
| _children['{%s}entry' % atom.ATOM_NAMESPACE] = ('entry', [PortfolioEntry]) |
| |
| |
| def PortfolioFeedFromString(xml_string): |
| return atom.CreateClassFromXMLString(PortfolioFeed, xml_string) |
| |
| |