Ejemplo n.º 1
0
def series_filter(predicate, s):
    
    '''For each observation in series, check the predicate against
    the value. Qualifying observations pass through to the output series.'''
    
    base_f = s.f
    def f(dt):
        val = base_f(dt)
        return val if (core.is_valid_num(val) and predicate(val)) else None
    name='filter({},{})'.format(abbreviate(predicate),abbreviate(s))
    return core.series(f, name=name)
Ejemplo n.º 2
0
    def binop_series_function(a, b):
        a = convert(a)
        b = convert(b)
        af = a.f
        bf = b.f

        def f(dt):
            a_val = af(dt)
            b_val = bf(dt)
            if core.is_valid_num(a_val) and core.is_valid_num(b_val):
                return op(a_val, b_val)

        name = '{}({},{})'.format(opname, abbreviate(a), abbreviate(b))
        return core.series(f, name=name)
Ejemplo n.º 3
0
def mo_days(s, days, dates=None):
    '''Similar to :code:`mo(s,N)`, :code:`mo_days(s,days)` calculates 
    the new/old ratios along the specified dates for each new, but 
    each old-date is based upon calendar days rather than periods.
    If the calendar days back does not line up with a market day, the
    value of most recent available earlier observation is selected.'''

    sf = s.f
    sf_old = (fudge(s)).f

    if days < 1:
        raise Exception('expected positive days')

    dates = dates or core.current_dates()
    dv = dates.vec
    fd = dv[0]
    outv = [None for dt in range(dv[0], dv[-1] + 1)]

    for dt in dates:
        r = ratio(sf_old(dt - days), sf(dt))
        if core.is_valid_num(r):
            outv[dt - fd] = r

    name = "mo_days({},{})".format(abbreviate(s), days)
    return core.vector_series(outv, fd, name=name)
Ejemplo n.º 4
0
def series_and(a, b):
    '''Given two series, return a series such that the output value is the value
    of the second input series if both input series have values at a date.'''

    af = a.f
    bf = b.f

    def f(dt):
        a_val = af(dt)
        if core.is_valid_num(a_val):
            b_val = bf(dt)
            if core.is_valid_num(b_val):
                return b_val
        return False

    name = 'and({},{})'.format(abbreviate(a), abbreviate(b))
    return core.series(f, name=name)
Ejemplo n.º 5
0
def series_or(a, b):
    '''Given two series, return a series such that the output value is the value
    from the first input series if that value is available. Otherwise, the
    the value from the second
    input series is returned.'''

    af = a.f
    bf = b.f

    def f(dt):
        result = af(dt)
        if is_valid_num(result):
            return result
        return bf(dt)

    name = 'or({},{})'.format(abbreviate(a), abbreviate(b))
    return core.series(f, name=name)
Ejemplo n.º 6
0
def fudge(s, days=6):
    '''fudge decorates a series such that the query by date 
    will continue looking backward until it finds a value,
    up to the number of days specified, defaulting to 
    six days.  Six days permits weekly and daily market 
    data to align dates with ends of 
    months, quarters and years.'''

    sf = s.f

    def f(dt):
        for i in range(days + 1):
            val = sf(dt - i)
            if core.is_valid_num(val):
                return val
        return None

    name = ("fudge({})".format(abbreviate(s))
            if days == 6 else "fudge({},{})".format(abbreviate(s), days))
    return core.series(f, name=name)
Ejemplo n.º 7
0
def to_signals(s, dates=None):
    '''Transform a series into non-repeating negative-one (-1) where the input is negative
       non-repeating one (1) where the input is non-negative.'''

    dates = dates or core.current_dates()
    vals = list(map(s.f, dates.vec))
    sigv = signalify_vector_copy(vals)

    fd = dates.first_date()
    ld = dates.last_date()
    outv = [None for dt in range(fd, ld + 1)]

    for (dt, sig) in zip(dates, sigv):
        if sig:
            outv[dt - fd] = sig

    return core.vector_series(outv, fd, name='sigs({})'.format(abbreviate(s)))
Ejemplo n.º 8
0
def fractional(s, fraction, dates=None):
    '''A fractional smoothes a series such that the current value is weighted by some fraction 
    in (0..1) added to the previous value weighted by (1 - fraction).'''

    dates = dates or core.current_dates()
    fd, ld = s.first_date(), s.last_date()
    outv = [None for dt in range(fd, ld + 1)]
    remainder = 1 - fraction
    prev = None
    f = s.f
    for dt in dates:
        val = f(dt)
        newVal = ((fraction * val + remainder * prev) if
                  (core.is_valid_num(prev)
                   and core.is_valid_num(val)) else val)
        outv[dt - fd] = newVal
        prev = newVal
    return core.vector_series(outv,
                              fd,
                              name="fractional({},{})".format(
                                  abbreviate(s), fraction))
Ejemplo n.º 9
0
def mo(s, N, dates=None):
    '''Return the N-period ratio series of new/old values.'''

    if N < 1:
        raise Exception('requires period > 0')

    dates = dates or core.current_dates()
    sf = s.f
    dv = dates.vec
    shifted_dv = dv[min(N, len(dv)):]
    outv = [None for dt in range(dv[0], dv[-1] + 1)]
    fd = dv[0]

    for (early, late) in zip(dv, shifted_dv):
        e_val = sf(early)
        l_val = sf(late)
        r = ratio(e_val, l_val)
        if core.is_valid_num(r):
            outv[late - fd] = r

    name = "mo({},{})".format(abbreviate(s), N)
    return core.vector_series(outv, fd, name=name)
Ejemplo n.º 10
0
def reversals(s, down_factor=1.0, up_factor=1.0, dates=None):
    '''When a series ascends above up-factor multiplied by a preceding 
    local minimum, a buy (1) signal is produced.  Upon 
    descending below the product of a local maximum and down-factor, 
    a sell (-1) signal is produced.
    '''
    dates = dates or core.current_dates()
    fd, ld = core.first_date(dates), core.last_date(dates)
    outv = [None for dt in range(fd, ld + 1)]
    min_ob = max_ob = first_ob(s, dates)
    sf = s.f
    state = None

    for dt in dates:

        val = sf(dt)
        if not core.is_valid_num(val):
            continue

        if val > max_ob[1]:
            max_ob = (dt, val)
        if val < min_ob[1]:
            min_ob = (dt, val)

        if (1 != state) and (val > min_ob[1] * up_factor):
            max_ob = min_ob = (dt, val)
            outv[dt - fd] = 1
            state = 1

        elif (-1 != state) and (val < max_ob[1] * down_factor):
            max_ob = min_ob = (dt, val)
            outv[dt - fd] = -1
            state = -1

    return core.vector_series(outv,
                              fd,
                              name="reversals({})".format(abbreviate(s)))
Ejemplo n.º 11
0
def calibrate(s, init=100, date=None):

    '''To calibrate a series is to make it value-compatible with another.
    For example, a spider graph picks a point at which multiple time
    series are the same value.  The default date is the beginning of the
    dateset and the default value of the series there is 100, making any
    value in the series equivalent to the percentage of the beginning.'''

    date = core.to_date(date) or core.first_date()
    f = s.f
    val = f(date)

    if not core.is_valid_num(val):
        raise Exception("no observation at {}".format(date))

    ratio = init / val

    def fetcher(dt):
        val = f(dt)
        if core.is_valid_num(val):
            val = val * ratio
        return val

    return core.series(fetcher, "calibrate({})".format(abbreviate(s)))