Пример #1
0
    def __init__(self, tickers=()):
        self._portfolio = {}

        self._transactions = slurp.transactions()

        portfolio_is_complete = False
        if bool(len(tickers) == 0):
            portfolio_is_complete = True
            tickers = tuple(api.symbols(remove='expired'))

        self._portfolio.update({
            ticker: stocks.Stock(self, ticker)
            for ticker in filter(api.whitelisted, tickers)
        })

        self._stocks = slurp.stocks(
            self._transactions,
            self._portfolio,
            portfolio_is_complete=portfolio_is_complete,
        )

        profile = api.rh.build_user_profile()
        self._equity = F(profile['equity'])
        self._extended_hours_equity = F(profile['extended_hours_equity'])
        self._cash = F(profile['cash'])
        self._dividends_total = F(profile['dividend_total'])
Пример #2
0
 def timed(*args, **kwargs):
     start = F(time())
     try:
         return func(*args, **kwargs)
     finally:
         MEASURED[func.__name__]['count'] += 1
         MEASURED[func.__name__]['time'] += F(time()) - start
Пример #3
0
def _option_orders():
    closed = defaultdict(list)
    premiums = defaultdict(lambda: 0)
    data = api.orders('options', 'all')
    for option in [o for o in data if o['state'] not in ('cancelled', )]:
        ticker = option['chain_symbol']

        strategies = []
        o, c = option['opening_strategy'], option['closing_strategy']
        if o:
            tokens = o.split('_')
            strategies.append('o[%s]' % ' '.join(tokens))
        if c:
            tokens = c.split('_')
            strategies.append('c[%s]' % ' '.join(tokens))

        legs = []
        premium = 0
        last_leg_strike_price = 0
        for leg in option['legs']:
            uri = leg['option']
            instrument = api.instrument(uri)

            legs.append('%s to %s K=%s X=%s' % (
                leg['side'],
                leg['position_effect'],
                util.color.mulla(instrument['strike_price']),
                instrument['expiration_date'],
            ))

            premium += sum([
                100 * F(x['price']) * F(x['quantity'])
                for x in leg['executions']
            ])

            last_leg_strike_price = instrument['strike_price']

        premium *= -1 if option['direction'] == 'debit' else +1
        premiums[ticker] += premium

        closed[ticker].append("%s %s %s x%s P=%s K=%s" % (
            option['state'],
            option['type'],
            '/'.join(strategies),
            util.color.qty(option['quantity'], 0),
            util.color.mulla(premium),
            util.color.mulla(last_leg_strike_price),
        ))

        for l in legs:
            closed[ticker].append(' + l:%s' % l)

    return dict(
        closed=closed,
        premiums=premiums,
    )
Пример #4
0
def ebitda(ticker):
    """
    Earnings Before Interest, Taxes, Depreciation and Amortization
    Used to measure the cash flow of a business.
    """
    key = 'EBITDA'
    return F(stats(ticker)[key])
Пример #5
0
def _qty(m):
    m = F(m)
    if isnan(m):
        return NaN, None

    if abs(m) < 1000:
        s = '{:,.2f}'.format(abs(m))
        c = 'red' if m < 0 else 'yellow'
    elif abs(m) < 1000000:
        s = '{:,}'.format(abs(round(m)))
        c = 'red' if m < 0 else 'green' if m >= 10000 else 'yellow'
    else:
        compressors = [
            ('K', 'yellow'),
            ('M', 'green'),
            ('B', 'blue'),
            ('T', 'magenta'),
        ]
        i = -1
        while abs(m) > 1000:
            m //= 1000
            i += 1
        s = '{:,.1f}'.format(abs(round(m)))
        if i > -1:
            s += compressors[i][0]
            c = compressors[i][1]
    return s, c
Пример #6
0
def dividends_paid(ticker):
    """
    This is dividends paid by the company, nothing to do with Robinhood profile and individual's
    account.
    """
    key = 'dividendsPaid'
    f = financials(ticker)
    return NaN if f is None else F(f[key])
Пример #7
0
def _sharpe_on_ticker(ticker):
    '''
    Sharpe Ratio for a single stock
    '''
    risk_free_ror = risk_free_rate_of_return()

    adj_close_price = slurp.stock_historic_prices(ticker)['Adj Close']
    daily_returns = adj_close_price.pct_change()
    returns_mean = F(np.mean(daily_returns))
    variance = daily_returns.cov(daily_returns)  # AKA ~np.var(daily_returns)
    volatility = F(np.sqrt(variance))  # AKA Standard Deviation, AKA Risk

    sharpe = util.numbers.NaN
    if volatility:
        sharpe = (ANNUAL_TRADING_DAYS * returns_mean -
                  risk_free_ror) / volatility

    return sharpe
Пример #8
0
def cp(ticker, cp):
    return F(
        stats(ticker)[dict(
            y5cp='year5ChangePercent',
            y2cp='year2ChangePercent',
            y1cp='year1ChangePercent',
            m6cp='month6ChangePercent',
            m3cp='month3ChangePercent',
            m1cp='month1ChangePercent',
            d30cp='day30ChangePercent',
            d5cp='day5ChangePercent',
        )[cp]])
Пример #9
0
def revenue(ticker, total=False, per=None):
    assert per is None or total is False

    if per == 'share':
        key = 'revenuePerShare'
    elif per == 'employee':
        key = 'revenuePerEmployee'
    elif total:
        key = 'totalRevenue'
    else:
        key = 'revenue'

    return F(stats(ticker)[key])
Пример #10
0
def ebit(ticker):
    """
    Earnings Before Interest and Taxes; also referred to as `operating earnings',
    `operating profit', and `profit before interest and taxes'.

    EBIT is used to measure a firm's operating income.

    EBIT can be calculated as revenue minus expenses excluding tax and interest.
    """

    key = 'ebit'
    f = financials(ticker)
    return NaN if f is None else F(f[key])
Пример #11
0
def ev(ticker, ratio=None):
    """
    Enterprise Value

    To calculate enterprise value, add the company's market capitalization to its outstanding
    preferred stock and all debt obligations, then subtract all of its cash and cash equivalents.
    """

    numerator = 'enterpriseValue'
    denominator = None

    if ratio == 'ev2r':
        numerator = 'enterpriseValueToRevenue'
    elif ratio == 'ev2gp':
        numerator = 'enterpriseValue'
        denominator = 'grossProfit'
    elif ratio == 'ev2ebitda':
        denominator = 'EBITDA'
    elif ratio == 'ebit2ev':
        denominator = numerator
        numerator = 'EBIT'

    s = stats(ticker)
    return F(s[numerator]) / F(1 if denominator is None else s[denominator])
Пример #12
0
def price(ticker, ratio=None):
    """
    Valuation Multiples/Ratios
    - P/E Ratio: what it is that you are actually paying for; aka, "earnings multiple"
    - P/E/G Ratio (G is expected growth)
    """
    if ratio is None:
        return _price_agg()[ticker]

    key = {
        'peg': 'pegRatio',
        'p2e': 'peRatio',
        'p2s': 'priceToSales',
        'p2b': 'priceToBook',
    }[ratio]

    return F(stats(ticker)[key])
Пример #13
0
def treynor(ticker, beta):
    '''
    Treynor Ratio for a single stock
    '''
    risk_free_ror = risk_free_rate_of_return()

    adj_close_price = slurp.stock_historic_prices(ticker)['Adj Close']
    daily_returns = adj_close_price.pct_change()
    returns_mean = F(np.mean(daily_returns))
    variance = daily_returns.cov(daily_returns)  # AKA ~np.var(daily_returns)
    volatility = beta  # AKA correlation to S&P500/Other Index, Risk

    sharpe = util.numbers.NaN
    if volatility:
        sharpe = (ANNUAL_TRADING_DAYS * returns_mean -
                  risk_free_ror) / volatility

    return sharpe
Пример #14
0
def _option_positions(prices):
    next_expiries = {}
    data = api.positions('options', 'all')
    collaterals = defaultdict(lambda: {'put': 0, 'call': 0})
    opened = defaultdict(list)
    urgencies = defaultdict(F)
    for option in [o for o in data if F(o['quantity']) != 0]:
        tocker = option['chain_symbol']
        ticker = api.tocker2ticker(tocker)
        price = F(prices[ticker])

        uri = option['option']
        instrument = api.instrument(uri)

        premium = 0
        if instrument['state'] != 'queued':
            premium -= F(option['quantity']) * F(option['average_price'])

        itype = instrument['type']
        otype = option['type']

        s_k_ratio = price / F(instrument['strike_price'])
        urgencies[ticker] = max(
            (urgencies[ticker], util.color.wtm_urgency(s_k_ratio, otype,
                                                       itype)))

        opened[ticker].append(
            "%s %s %s x%s P=%s K=%s X=%s %s" %
            (instrument['state'], util.color.otype(otype),
             util.color.itype(itype), util.color.qty(
                 option['quantity'], 0), util.color.mulla(premium),
             util.color.mulla(
                 instrument['strike_price']), instrument['expiration_date'],
             util.color.wtm(s_k_ratio, otype, itype)))
        expiry = util.datetime.parse(instrument['expiration_date'])
        if next_expiries.get(ticker) is None:
            next_expiries[ticker] = expiry
        else:
            next_expiries[ticker] = min(next_expiries[ticker], expiry)

        collaterals[ticker][itype] += 100 * F(
            dict(put=instrument['strike_price'],
                 call=option['quantity'])[itype])

    return dict(
        collaterals=collaterals,
        urgencies=urgencies,
        next_expiries=next_expiries,
        opened=opened,
    )
Пример #15
0
def roe(ticker):
    """
    Return on equity (ROE) is a measure of financial performance calculated by dividing net
    income by shareholders' equity. Because shareholders' equity is equal to a company’s assets
    minus its debt, ROE is considered the return on net assets. ROE is considered a measure of
    the profitability of a corporation in relation to stockholders’ equity.

    https://www.investopedia.com/terms/r/returnonequity.asp

    The ROE bridges the gap between the income statement and the balance sheet.

    ROE analysis is unreliable when:
    - special dividends
    - negative equity (cash buybacks)
    - negative equity (recent return to profitability)
    - no peer group (ROE is only meaningful when used comparitively)
    """
    netinc = earnings(ticker)
    bs = balancesheet(ticker, period='quarter', last=1)

    if len(bs) == 0:
        return NaN

    return netinc / F(bs[0]['shareholderEquity'])
Пример #16
0
def _extensions(S, T):
    return (
        Field(
            name='roe',
            getter=SimpleField(caller=api.roe),
            pullcast=F,
            pushcast=util.color.mpct,
            description='Return On Equity',
            documentation='https://www.investopedia.com/terms/r/returnonequity.asp',
        ),
        Field(
            name='roic',
            getter=SimpleField(caller=api.roic),
            pullcast=F,
            pushcast=util.color.pct,
            description='ROIC',
            documentation='https://www.investopedia.com/terms/r/returnoninvestmentcapital.asp',
        ),
        Field(
            name='ebt',
            getter=SimpleField(caller=api.ebt),
            pullcast=F,
            pushcast=util.color.mulla,
            description='EBT',
            documentation='https://www.investopedia.com/terms/e/ebt.asp',
        ),
        Field(
            name='ebit',
            getter=SimpleField(caller=api.ebit),
            pullcast=F,
            pushcast=util.color.mulla,
            description='EBIT',
            documentation='https://www.investopedia.com/terms/e/ebit.asp',
        ),
        Field(
            name='ebitda',
            getter=SimpleField(caller=api.ebitda),
            pullcast=F,
            pushcast=util.color.mulla,
            description='EBITDA',
            documentation='https://www.investopedia.com/terms/e/ebitda.asp',
        ),
        Field(
            name='p2e',
            getter=SimpleField(caller=lambda ticker: api.price(ticker, ratio='p2e')),
            pullcast=F,
            pushcast=util.color.qty,
            description='P/E Ratio',
            documentation='https://www.investopedia.com/terms/i/industry.asp',
        ),
        Field(
            name='p2b',
            getter=SimpleField(caller=lambda ticker: api.price(ticker, ratio='p2b')),
            pullcast=F,
            pushcast=util.color.qty,
            description='P/B Ratio',
            documentation='https://www.investopedia.com/terms/i/industry.asp',
        ),
        Field(
            name='p2s',
            getter=SimpleField(caller=lambda ticker: api.price(ticker, ratio='p2s')),
            pullcast=F,
            pushcast=util.color.qty,
            description='P/S Ratio',
            documentation='https://www.investopedia.com/terms/i/industry.asp',
        ),
        Field(
            name='peg',
            getter=SimpleField(caller=lambda ticker: api.price(ticker, ratio='peg')),
            pullcast=F,
            pushcast=util.color.qty,
            description='PEG Ratio',
            documentation='https://www.investopedia.com/terms/i/industry.asp',
        ),
        Field(
            name='industry',
            getter=SimpleField(caller=api.industry),
            pullcast=str,
            pushcast=util.color.colhashwrap,
            description='Industry',
            documentation='https://www.investopedia.com/terms/i/industry.asp',
        ),
        Field(
            name='sector',
            getter=SimpleField(caller=api.sector),
            pullcast=str,
            pushcast=util.color.colhashwrap,
            description='Sector',
            documentation='https://www.investopedia.com/terms/s/sector.asp',
        ),
        Field(
            name='ev',
            getter=SimpleField(caller=api.ev),
            pullcast=F,
            pushcast=util.color.mulla,
            description='Enterprise Value; the market value plus the net interest-bearing debt',
            documentation='https://www.investopedia.com/ask/answers/111414/whats-difference-between-enterprise-value-and-market-capitalization.asp',
        ),
        Field(
            name='so',
            getter=SimpleField(caller=api.shares_outstanding),
            pullcast=F,
            pushcast=util.color.qty0,
            description='Shares Outstanding',
            documentation='https://www.investopedia.com/terms/o/outstandingshares.asp',
        ),
        Field(
            name='marketcap',
            getter=SimpleField(caller=api.marketcap),
            pullcast=F,
            pushcast=util.color.mulla,
            description='Market Capitalization',
            documentation='https://www.investopedia.com/terms/m/marketcapitalization.asp',
        ),
        Field(
            name='beta',
            getter=SimpleField(caller=api.beta),
            pullcast=F,
            pushcast=util.color.qty,
            description='Beta',
            documentation='https://www.investopedia.com/terms/b/beta.asp',
        ),
        Field(
            name='premium_collected',
            getter=None,
            pullcast=F,
            pushcast=util.color.mulla,
            description='Options Premium Collected',
            documentation='',
        ),
        Field(
            name='dividends_collected',
            getter=None,
            pullcast=F,
            pushcast=util.color.mulla,
            description='Stock Dividends Collected',
            documentation='',
        ),
        Field(
            name='d50ma',
            getter=SimpleField(caller=lambda ticker: api.ma(ticker, 'd50ma')),
            pullcast=F,
            pushcast=util.color.mulla,
            description='50-Day Moving Average',
            documentation='',
        ),
        Field(
            name='d200ma',
            getter=SimpleField(caller=lambda ticker: api.ma(ticker, 'd200ma')),
            pullcast=F,
            pushcast=util.color.mulla,
            description='200-Day Moving Average',
            documentation='',
        ),
        Field(
            name='y5c%',
            getter=SimpleField(caller=lambda ticker: api.cp(ticker, 'y5cp')),
            pullcast=F,
            pushcast=util.color.mpct,
            description='5-Year Percentage Change',
            documentation='',
        ),
        Field(
            name='y2c%',
            getter=SimpleField(caller=lambda ticker: api.cp(ticker, 'y2cp')),
            pullcast=F,
            pushcast=util.color.mpct,
            description='2-Year Percentage Change',
            documentation='',
        ),
        Field(
            name='y1c%',
            getter=SimpleField(caller=lambda ticker: api.cp(ticker, 'y1cp')),
            pullcast=F,
            pushcast=util.color.mpct,
            description='1-Year Percentage Change',
            documentation='',
        ),
        Field(
            name='m6c%',
            getter=SimpleField(caller=lambda ticker: api.cp(ticker, 'm6cp')),
            pullcast=F,
            pushcast=util.color.mpct,
            description='6-Month Percentage Change',
            documentation='',
        ),
        Field(
            name='m3c%',
            getter=SimpleField(caller=lambda ticker: api.cp(ticker, 'm3cp')),
            pullcast=F,
            pushcast=util.color.mpct,
            description='3-Month Percentage Change',
            documentation='',
        ),
        Field(
            name='m1c%',
            getter=SimpleField(caller=lambda ticker: api.cp(ticker, 'm1cp')),
            pullcast=F,
            pushcast=util.color.mpct,
            description='1-Month Percentage Change',
            documentation='',
        ),
        Field(
            name='d30c%',
            getter=SimpleField(caller=lambda ticker: api.cp(ticker, 'd30cp')),
            pullcast=F,
            pushcast=util.color.mpct,
            description='30-Day Percentage Change',
            documentation='',
        ),
        Field(
            name='d5c%',
            getter=SimpleField(caller=lambda ticker: api.cp(ticker, 'd5cp')),
            pullcast=F,
            pushcast=util.color.mpct,
            description='5-Day Percentage Change',
            documentation='',
        ),
        Field(
            name='d1c%',
            getter=SimpleField(caller=lambda ticker: api.quote(ticker)['changePercent']),
            pullcast=F,
            pushcast=util.color.mpct,
            description="Change percent from previous trading day's close",
            documentation='',
        ),
        Field(
            name='malps%',
            getter=ComplexField(
                attributes=[
                    'd200ma', 'd50ma', 'price',
                ],
                chain=[
                    lambda R: list(R.values()),
                    lambda R: -util.numbers.growth_score(R) / R[-1],
                ],
            ),
            pullcast=F,
            pushcast=util.color.mpct,
            description='Moving average loss per dollar of share',
            documentation='',
        ),
        Field(
            name='cbps',
            getter=ComplexField(
                attributes=['ticker'],
                chain=[
                    lambda R: T[T['symbol'] == R['ticker']],
                    lambda df: df['cbps'].values[-1],
                ]
            ),
            pullcast=F,
            pushcast=util.color.mulla,
            description='Cost-Basis per Share (Excluding Option Premiums and Dividends',
            documentation='https://www.investopedia.com/terms/c/costbasis.asp',
        ),
        Field(
            name='cbps%',
            getter=ComplexField(
                attributes=['ticker'],
                chain=[
                    lambda R: (
                        T[T['symbol'] == R['ticker']]['cbps'].values[-1]
                    ) / (
                        S[S['ticker'] == R['ticker']].price.item()
                    ),
                ]
            ),
            pullcast=F,
            pushcast=util.color.mpct,
            description='Cost-Basis per Share (as a percentage of share price)',
            documentation='https://www.investopedia.com/terms/c/costbasis.asp',
        ),
        Field(
            name='dyps%',
            getter=ComplexField(
                attributes=['ticker'],
                chain=[
                    lambda R: R['ticker'],
                    lambda ticker: dict(
                        price=np.mean((
                            api.ma(ticker, ma='d200ma'),
                            api.ma(ticker, ma='d50ma'),
                            api.price(ticker),
                        )),
                        divs=list(zip(*(
                            (F(div['amount']), F(div['position']))
                            for div in api.dividends(ticker)
                        ))),
                    ),
                    lambda d: sum(
                        d['divs'][0]  # dividend amount
                    ) / sum(
                        d['divs'][1]  # number of stocks held at time of dividend payout
                    ) / (
                        d['price']    # recency-weighted average of share price
                    ) if len(d['divs']) > 0 else 0,
                ]
            ),
            pullcast=F,
            pushcast=util.color.mpct,
            description='Dividend yield per dollar of share price',
            documentation='...',
        ),
        Field(
            name='pcps%',
            getter=ComplexField(
                attributes=['ticker'],
                chain=[
                    lambda R: R['ticker'],
                    lambda ticker: dict(
                        price=np.mean((
                            api.ma(ticker, ma='d200ma'),
                            api.ma(ticker, ma='d50ma'),
                            api.price(ticker),
                        )),
                        premcol=S[S['ticker'] == ticker]['premium_collected'],
                        bought=T[T['symbol'] == ticker]['bought'].tail(1).item(),
                    ),
                    lambda d: (
                        d['premcol']  # premium collected in total
                    ) / (
                        d['bought']   # number of shares ever purchased
                    ) / (
                        d['price']    # recency-weighted average of share price
                    ),
                ]
            ),
            pullcast=F,
            pushcast=util.color.mpct,
            description='Premium collected per dollar of share price ever purchased',
            documentation='...',
        ),
        Field(
            name='first_traded',
            getter=ComplexField(
                attributes=['ticker'],
                chain=[
                    lambda R: T[T['symbol'] == R['ticker']].date,
                    lambda dates: min(dates) if len(dates) else -1,
                ]
            ),
            pullcast=util.datetime.datetime,
            pushcast=lambda d: util.color.qty0(util.datetime.age(d)),
            description='Days since first trade',
            documentation='',
        ),
        Field(
            name='last_traded',
            getter=ComplexField(
                attributes=['ticker'],
                chain=[
                    lambda R: T[T['symbol'] == R['ticker']].date,
                    lambda dates: max(dates) if len(dates) else 999,
                ]
            ),
            pullcast=util.datetime.datetime,
            pushcast=lambda d: util.color.qty0(util.datetime.age(d)),
            description='Days since last trade',
            documentation='',
        ),
        Field(
            name='momentum',
            getter=ComplexField(
                attributes=[
                    'y5c%', 'y2c%', 'y1c%',
                    'm6c%', 'm3c%', 'm1c%',
                    'd30c%', 'd5c%',
                    'roe',
                ],
                chain=[
                    lambda R: [
                        sp.stats.percentileofscore(S[period], value)
                        for period, value in R.items()
                    ],
                    statistics.mean,
                    lambda pct: pct / 100.0,
                ]
            ),
            pullcast=F,
            pushcast=util.color.mpct,
            description='Momentum Percentile (compared to the rest of this Portfolio)',
            documentation='',
        ),
        Field(
            name='analyst_score',
            getter=ComplexField(
                attributes=['ticker'],
                chain=[
                    lambda R: R['ticker'],
                    api.ratings,
                ],
            ),
            pullcast=F,
            pushcast=util.color.qty,
            description='Analyst (Morning Star) Ratings, converted to a single number',
            documentation='',
        ),
        Field(
            name='you_score%',
            getter=ComplexField(
                attributes=['cbps%', 'dyps%', 'pcps%'],
                chain=[
                    lambda R: [
                        sp.stats.percentileofscore(S[period], value)
                        for period, value in R.items()
                    ],
                    statistics.mean
                ]
            ),
            pullcast=F,
            pushcast=util.color.pct,
            description='You-Score for owning this stock (how well has the investor done)',
            documentation='',
        ),
        Field(
            name='stock_score%',
            getter=ComplexField(
                attributes=['malps%', 'momentum'],
                chain=[
                    lambda R: R.values(),
                    sum,
                ]
            ),
            pullcast=F,
            pushcast=util.color.mpct,
            description='Stock-Score (how well has the stock done)',
            documentation='',
        ),
        Field(
            name='sharpe',
            getter=ComplexField(
                attributes=['ticker'],
                chain=[
                    lambda R: models.sharpe(ticker=R['ticker']),
                ]
            ),
            pullcast=F,
            pushcast=util.color.pct,
            description='Sharpe Ratio',
            documentation='https://www.investopedia.com/terms/s/sharperatio.asp',
        ),
        Field(
            name='treynor',
            getter=ComplexField(
                attributes=[
                    'ticker', 'beta'
                ],
                chain=[
                    lambda R: models.treynor(R['ticker'], R['beta']),
                ]
            ),
            pullcast=F,
            pushcast=util.color.pct,
            description='Treynor Ratio',
            documentation='https://www.investopedia.com/terms/t/treynorratio.asp',
        ),
        Field(
            name='ebit2ev',
            getter=ComplexField(
                attributes=['ebit', 'ev'],
                chain=[
                    lambda R: R['ebit'] / R['ev'],
                ]
            ),
            pullcast=F,
            pushcast=util.color.mpct,
            description='Earnings yield; what the business earns in relation to its share price',
            documentation='',
        ),
    )
Пример #17
0
def _pull_processed_holdings_data(portfolio):
    now = util.datetime.now()
    data = []

    with ShadyBar('%48s' % 'Refreshing Robinhood Portfolio Data',
                  max=len(portfolio) + 3) as bar:
        # 1. Pull holdings
        holdings = api.holdings()
        bar.next()

        # 2. Pull Option Positions
        _data = _option_positions(api._price_agg())
        collaterals = _data['collaterals']
        next_expiries = _data['next_expiries']
        urgencies = _data['urgencies']
        opened = _data['opened']
        del _data
        bar.next()

        # 3. Pull Options Orders
        _data = _option_orders()
        premiums = _data['premiums']
        closed = _data['closed']
        del _data
        bar.next()

        # 4. Add all rows to Python list first
        _timers = {}
        for ticker, stock in portfolio.items():
            bar.next()

            if ticker not in holdings:
                continue

            holding = holdings[ticker]

            _opened = '\n'.join(opened.get(ticker, []))
            _closed = '\n'.join(closed.get(ticker, []))
            _collateral = F(collaterals[ticker]['call'])
            _optionable = (F(holding['quantity']) - _collateral) // 100
            activities_data = []
            if _opened: activities_data.append(_opened)
            if _closed: activities_data.append(_closed)
            if _optionable > 0:
                activities_data.append('%sx100 available' %
                                       (util.color.qty0(_optionable)))
            activities = ('\n%s\n' % ('─' * 32)).join(activities_data)

            collateral = collaterals[ticker]
            premium = premiums[ticker]
            dividend = api.dividends(ticker)
            next_expiry = next_expiries.get(ticker, pd.NaT)
            ttl = util.datetime.delta(now,
                                      next_expiry).days if next_expiry else -1
            #fundamentals = api.fundamentals(ticker)
            quote = api.quote(ticker)

            row = dict(
                ticker=ticker,
                price=api.price(ticker),
                pcp=F(quote['previousClose']),
                beta=api.beta(ticker),
                quantity=holding['quantity'],
                average_buy_price=holding['average_buy_price'],
                equity=holding['equity'],
                percent_change=holding['percent_change'],
                equity_change=holding['equity_change'],
                type=holding['type'],
                name=holding['name'],
                percentage=holding['percentage'],
                cnt=len(stock.events),
                trd=stock.traded(),
                qty=stock._quantity,
                premium_collected=premium,
                dividends_collected=sum(F(div['amount']) for div in dividend),
                collateral_call=F(collateral['call']),
                collateral_put=F(collateral['put']),
                ttl=ttl,
                urgency=urgencies[ticker],
                activities=activities,
                next_expiry=next_expiry,
            )
            data.append(row)

    return data
Пример #18
0
        def _costbasis(row):
            if api.blacklisted(row.symbol, full=True):
                return pd.Series([NaN, NaN, NaN, NaN])

            data = cbtally[row.symbol]

            signum = {'buy': -1, 'sell': +1}[row.side]
            datum = [
                'trade',
                F(signum) * F(row.quantity),
                F(row.average_price), row.date
            ]

            if len(data) > 0:
                _, _, _, d0 = data[-1]
                _, _, _, d2 = datum
                splits = api.splits(row.symbol)
                for split in splits:
                    d1 = util.datetime.parse(split['exDate'])
                    if not d0 < d1 < d2:
                        continue

                    for existing in data:
                        existing[1] *= F(split['toFactor'])
                        existing[1] /= F(split['fromFactor'])
                        existing[2] *= F(split['fromFactor'])
                        existing[2] /= F(split['toFactor'])

            data.append(datum)
            _, _, price, _ = datum

            bought = -sum(qty for cls, qty, pps, date in data if qty < 0)
            sold = +sum(qty for cls, qty, pps, date in data if qty > 0)
            held = bought - sold

            return pd.Series([
                F(bought),
                F(sold),
                F(held),
                F((sum(qty * pps
                       for cls, qty, pps, date in data) + held * price) /
                  bought) if bought > 0 else 0
            ])
Пример #19
0
 def price(self):
     return F(api.price(self.ticker))
Пример #20
0
 def beta(self):
     return F(api.beta(self.ticker))
Пример #21
0
 def intrades(self):
     return {
         t['transactionDate']: F(t['transactionShares'])
         for t in api.insider_transactions(self.ticker)
     }
Пример #22
0
 def marketcap(self):
     return F(api.marketcap(self.ticker))
Пример #23
0
from util.numbers import F


def colorize(f, n, d, v):
    c = d[0]
    if not isnan(n):
        for i, v in enumerate(v):
            if v < n:
                c = d[i + 1]

    return colored(f(n), c)


# Percentage
spc = ['red', 'yellow', 'green', 'cyan', 'magenta']
pct = lambda p: colorize(lambda n: '%0.2f%%' % n, F(p), spc,
                         [F(0), F(50), F(65), F(80)])
mpct = lambda p: pct(100 * p)

spcr = ['blue', 'cyan', 'green', 'yellow', 'red']
pctr = lambda p: colorize(lambda n: '%0.2f%%' % n, F(p), spcr,
                          [F(0), F(50), F(65), F(80)])
mpctr = lambda p: pctr(100 * p)


# Quantity
def _qty(m):
    m = F(m)
    if isnan(m):
        return NaN, None
Пример #24
0
def _sharpe_on_holdings(holdings):
    '''
    holdings: api.rh.build_holdings()
    '''
    df = pd.DataFrame(index=None)
    equities = {}
    with ShadyBar('%32s' % 'Pulling Historic Quote Prices',
                  max=len(holdings)) as bar:
        for ticker, datum in holdings.items():
            df[ticker] = slurp.stock_historic_prices(ticker)['Adj Close']
            equities[ticker] = F(datum['equity'])
            bar.next()

    # Calculate the current weight of each stock in the portfolio
    equity = sum(equities.values())
    weights = np.array(
        [equities[ticker] / equity for ticker in equities.keys()],
        dtype=np.float)

    # Calculate historic returns (percentage change close-to-close)
    returns = df.pct_change()

    # Number of Trading Days per Year (roughly)
    annual_trading_days = int(365 * 5 / 7 - 6 - 3 * 5 / 7)

    # Calculate the Annual Covariance
    # - The diagonal of this matrix is the variance (sqrt of the variance is volatility)
    # - Every other cell is the covariance (between the two non-identical tickes)
    annual_covariance = returns.cov() * annual_trading_days

    # Calculate the Portfolio Variance
    annual_variance = np.dot(weights.T, np.dot(annual_covariance, weights))

    # Calculate the Portfolio Volatility
    annual_volatility = np.sqrt(annual_variance)

    # Calculate the Simple Annual Return
    simple_annual_return = np.sum(returns.mean() * weights *
                                  annual_trading_days)

    # Measure the Portfolio
    response = dict(status_quo=dict(
        expected_annual_return=simple_annual_return,
        annual_volatility=annual_volatility,
        annual_variance=annual_variance,
    ),
                    efficient_frontier=dict())

    # Improve the Portfolio
    # Calculate expected returns and annualized sample covariance matrix of asset returns
    mu = ppo.expected_returns.mean_historical_return(df)
    S = ppo.risk_models.sample_cov(df)

    # Optimize for max sharpe ratio (k) - measures the performance of the porfolio compared
    # to risk-free investments like bonds or treasuries
    ef = EfficientFrontier(mu, S)
    reweighted = ef.max_sharpe()
    cleanweighted = ef.clean_weights()

    response['efficient_frontier']['portfolio'] = {
        ticker: pct
        for ticker, pct in cleanweighted.items() if pct > 0
    }

    expected_annual_return, annual_volatility, sharpe_ratio = ef.portfolio_performance(
    )
    risk_free_ror = expected_annual_return - sharpe_ratio * annual_volatility
    response['efficient_frontier']['expectation'] = dict(
        expected_annual_return=expected_annual_return,
        annual_volatility=annual_volatility,
        sharpe_ratio=sharpe_ratio,
        risk_free_ror=risk_free_ror,
    )

    response['status_quo']['risk_free_rate'] = risk_free_ror
    response['status_quo']['sharpe_ratio'] = (
        simple_annual_return - risk_free_ror) / annual_volatility

    return response
Пример #25
0
def risk_free_rate_of_return():
    '''
    TODO: Make this dynamic
    '''
    return F(0.02)
Пример #26
0
import numpy as np
import pandas as pd
from pypfopt.efficient_frontier import EfficientFrontier
import pypfopt as ppo

from progress.bar import ShadyBar

import slurp
import util
from util.numbers import F

ANNUAL_TRADING_DAYS = F(365 * 5 / 7 - 6 - 3 * 5 / 7)


def risk_free_rate_of_return():
    '''
    TODO: Make this dynamic
    '''
    return F(0.02)


def treynor(ticker, beta):
    '''
    Treynor Ratio for a single stock
    '''
    risk_free_ror = risk_free_rate_of_return()

    adj_close_price = slurp.stock_historic_prices(ticker)['Adj Close']
    daily_returns = adj_close_price.pct_change()
    returns_mean = F(np.mean(daily_returns))
    variance = daily_returns.cov(daily_returns)  # AKA ~np.var(daily_returns)
Пример #27
0
def _wtm(s_k_ratio, otype, itype):
    '''
    Where-The-Money?

    otype: short / long
    itype: call / put

    S: Current Price
    K: Strike Price

    S_K_Ratio: S/K
    '''

    keys = ['DITM', 'ITM', 'ATM', 'OTM', 'WOTM']
    thresholds = [F(0.75), F(0.95), F(1 / 0.95), F(1 / 0.75)]

    index = 0
    for i, limit in enumerate(thresholds):
        if s_k_ratio >= limit:
            index = i + 1
        else:
            break

    style = {
        'call': [
            ('red', ('reverse', )),
            ('red', ()),
            ('yellow', ('reverse', 'blink')),
            ('cyan', ()),
            ('cyan', ('reverse', )),
        ],
        'put': [
            ('red', ('reverse', )),
            ('red', ()),
            ('yellow', ('reverse', 'blink')),
            ('green', ()),
            ('green', ('reverse', )),
        ]
    }[itype]

    themoney = {
        'put': keys[index],
        'call': keys[len(thresholds) - index],
    }[itype]

    style = {
        'short': style,
        'long': reversed(style),
    }[otype]

    # how likely it is that this contract will not expire worthless, and that it will
    # be assigned if seller, and hold intrinsic value if buyer
    impact = [F(0.40), F(0.7), F(1), F(1.3), F(1.6)]
    urgency = {
        'put': F(1) / F(s_k_ratio) * impact[len(thresholds) - index],
        'call': F(s_k_ratio) * impact[index],
    }[itype]
    urgency = {
        'short': urgency,
        'long': F(1) / urgency,
    }[otype]

    c, attrs = dict(zip(keys, style))[themoney]
    return dict(
        style_c=c,
        style_attrs=attrs,
        urgency=urgency,
        string=themoney,
    )
Пример #28
0
def mstart(name):
    assert 'activesince' not in MEASURED[name]
    MEASURED[name]['activesince'] = F(time())
Пример #29
0
def mulla(m):
    m = F(m)
    s, c = _qty(m)
    return colored(('+$%s' if m > 0 else '-$%s') % s, c)
Пример #30
0
def mstop(name):
    assert 'activesince' in MEASURED[name]
    MEASURED[name]['count'] += 1
    MEASURED[name]['time'] = F(time()) - MEASURED[name]['activesince']
    del MEASURED[name]['activesince']