def common_ts_setup(): series2D = ts.time_series([np.random.rand(25).reshape(5,5), np.random.rand(25).reshape(5,5), np.random.rand(25).reshape(5,5), np.random.rand(25).reshape(5,5), np.random.rand(25).reshape(5,5),], start_date=ts.now('M'), mask=[np.random.rand(25).reshape(5,5)>.5, np.random.rand(25).reshape(5,5)>.5, np.random.rand(25).reshape(5,5)>.5, np.random.rand(25).reshape(5,5)>.5, np.random.rand(25).reshape(5,5)>.5,] ) series1D = ts.time_series(np.random.rand(25), mask=np.random.rand(25)>0.7, start_date=ts.now('M'), fill_value=-999) series5V = ts.time_series(np.random.rand(25).reshape(5,5), mask=np.random.rand(25).reshape(5,5)>0.7, start_date=ts.now('M')) series5N = ts.time_series(zip(np.random.rand(5), np.random.rand(5), np.arange(5)), start_date=ts.now('M'), dtype=[('a',float),('b',float),('c',int)] ) return dict(series1D=series1D, series5V=series5V, series2D=series2D, series5N=series5N)
def common_ts_setup(): series2D = ts.time_series([ np.random.rand(25).reshape(5, 5), np.random.rand(25).reshape(5, 5), np.random.rand(25).reshape(5, 5), np.random.rand(25).reshape(5, 5), np.random.rand(25).reshape(5, 5), ], start_date=ts.now('M'), mask=[ np.random.rand(25).reshape(5, 5) > .5, np.random.rand(25).reshape(5, 5) > .5, np.random.rand(25).reshape(5, 5) > .5, np.random.rand(25).reshape(5, 5) > .5, np.random.rand(25).reshape(5, 5) > .5, ]) series1D = ts.time_series(np.random.rand(25), mask=np.random.rand(25) > 0.7, start_date=ts.now('M'), fill_value=-999) series5V = ts.time_series(np.random.rand(25).reshape(5, 5), mask=np.random.rand(25).reshape(5, 5) > 0.7, start_date=ts.now('M')) series5N = ts.time_series(zip(np.random.rand(5), np.random.rand(5), np.arange(5)), start_date=ts.now('M'), dtype=[('a', float), ('b', float), ('c', int)]) return dict(series1D=series1D, series5V=series5V, series2D=series2D, series5N=series5N)
def parse_instrument(instrument): S = {} t=ts.now('D') S['START']=ts.Date(freq="D",datetime=datetime.date(t.year,1,1)) S['END']=ts.Date(freq='D',datetime=datetime.date(t.year,12,31)) S['FREQ']='D' S['NAN']=True m = re_instrument.match(instrument) if m: logger.debug('Match instrument |%s| %s',instrument,m.lastindex) ticker,specs = m.groups() logger.debug('|%s| -- %s', len(ticker),specs) if len(ticker)==0: ticker=u"E4T" S['TICKER']=str(ticker) logger.debug('Match ticker %s',ticker) if specs: parts = specs[1:].split('~') for part in parts: logger.debug('Match part %s',part) if part[0]==':': S['END']=match_date(part[1:]) elif re.match('\[([0-9]+)\]',part): print "GOT",part m=re.match('\[([0-9]+)\]',part) S['START']=0 S['END']=int(m.group(1)) S['FREQ']='0' elif re.match('!',part[0]): S['NAN']=False elif re.match('[0-9]',part[0]): S['START']=match_date(part) S['KIND']='T' elif re.match('M|Q|A|D|Y',part[0]): S['FREQ']=str(part[0]) logger.debug('parsed: %s',S) if 'END' in S: d = S['END'] df = d.asfreq(S['FREQ'],relation='START') logger.debug('modify END: %s %s',d,df) S['END']=S['END'].asfreq(S['FREQ']) if 'START' in S: logger.debug('modify START: %s',S['START']) S['START']=S['START'].asfreq(S['FREQ']) logger.debug('parsed: %s',S) logger.debug('parsed') else: logger.debug('Cant match instrument |%s|',instrument) logger.debug('parsed: %s',S) if 'FREQ' not in S: S['FREQ']='D' if 'END' not in S: S['END']=ts.now(str(S['FREQ'])) if 'START' not in S: S['START']=ts.now(str(S['FREQ']))-(365 if S['FREQ']=='D' else 24 if S['FREQ']=='M' else 12 if S['FREQ']=='Q' else 10 ) logger.debug('parsed: %s',S) return S
def setup(self): a = time_series(np.random.rand(24), start_date=ts.now('M')) b = time_series(np.random.rand(24) * 100, dtype=int, start_date=ts.now('M'),) # c = time_series(["%02i" % _ for _ in np.arange(24)], # start_date=ts.now('M')) c = time_series(np.arange(24), start_date=ts.now('M')) trec = fromarrays([a, b, c], dates=a.dates, names='a,b,c') self.info = (a, b, c, trec)
def setup(self): a = time_series(np.random.rand(24), start_date=ts.now('M')) b = time_series( np.random.rand(24) * 100, dtype=int, start_date=ts.now('M'), ) # c = time_series(["%02i" % _ for _ in np.arange(24)], # start_date=ts.now('M')) c = time_series(np.arange(24), start_date=ts.now('M')) trec = fromarrays([a, b, c], dates=a.dates, names='a,b,c') self.info = (a, b, c, trec)
def add_diurnal(tseries, sine_period, peak_mag): """ Scales a time series to a sine wave of peak_mag with sine_period. Input: tseries, sine_period (float, hrs), peak_mag (float) Output: scaled_data (array-like) """ # Convert sine_period to same frequency as tseries # Create a time delta of magnitude sine_period # Convert that time delta into frequency units same as tseries zero_date = ts.now('H') second_date = zero_date + sine_period time_delta = ts.date_array([zero_date, second_date]) time_delta = time_delta.asfreq(tseries.freq) sine_period = float(time_delta[1] - time_delta[0]) angular_freq = (2. * np.pi) / sine_period for i in range(len(tseries)-1): passed_time = float(tseries.dates[i]- tseries.start_date) sine_factor = peak_mag * np.sin(angular_freq * passed_time) tseries[i] = tseries[i] + tseries[i] * sine_factor return tseries # Generate power density function (pdf) to create synthetic TPM from # mean, stdev, autocorr, npointsx # def gen_pdf(desired_mean, desired_stdev, bin_width): ## TODO return 0
def test_apply_on_fields_series(self): "Test apply_on_fields w/ time_series" adtype = [('fi', int), ('ff', float)] a = ts.time_series([(1, 1.), (2, 2.), (3, 3.)], mask=[(0, 0), (0, 1), (0, 0)], dtype=adtype, start_date=ts.now('M')) func = ma.cumsum test = apply_on_fields(a, func) control = ts.time_series([(1, 1.), (3, -1), (6, 4.)], mask=[(0, 0), (0, 1), (0, 0)], dtype=adtype, start_date=ts.now('M')) assert_equal(test, control) self.failUnless(isinstance(test, ts.TimeSeries)) assert_equal(test.dates, control.dates)
def setUp(self): (a, b) = (np.arange(10), np.random.rand(10)) ndtype = [('a', np.float), ('b', np.float)] tarr = ts.time_series(np.array(zip(a, b), dtype=ndtype), start_date=ts.now('M')) tarr.mask[3] = (False, True) self.data = (tarr, a, b)
def test_ontimeseries(self): "Test cmov_average on a 1D TimeSeries." data = ts.time_series(self.maskeddata, start_date=ts.now("D")) for width in [3, 5, 7]: k = (width - 1) / 2 ravg = mf.cmov_average(data, width) self.failUnless(isinstance(ravg, MaskedArray)) assert_equal(ravg, data) m = np.zeros(len(data), bool) m[:k] = m[-k:] = m[10 - k : 10 + k + 1] = True assert_equal(ravg._mask, m) assert_equal(ravg._dates, data._dates)
def test_ontimeseries(self): "Test cmov_average on a 1D TimeSeries." data = ts.time_series(self.maskeddata, start_date=ts.now('D')) for width in [3, 5, 7]: k = (width - 1) / 2 ravg = mf.cmov_average(data, width) self.failUnless(isinstance(ravg, MaskedArray)) assert_equal(ravg, data) m = np.zeros(len(data), bool) m[:k] = m[-k:] = m[10 - k:10 + k + 1] = True assert_equal(ravg._mask, m) assert_equal(ravg._dates, data._dates)
def __init__(self, *args, **kwds): TestCase.__init__(self, *args, **kwds) series = ts.time_series(zip(np.random.rand(10), np.arange(10)), start_date=ts.now('M'), dtype=[('a', float), ('b', int)]) series.mask[0] = (0, 1) series.mask[-1] = (1, 0) self.tseries = series self.marray = series._series self.file = tempfile.mktemp(".hdf5") self.h5file = tables.openFile(self.file, 'a') self.populate()
def __init__(self, *args, **kwds): TestCase.__init__(self, *args, **kwds) self.marray = ma.array(np.random.rand(100).reshape(10,10), mask = (np.random.rand(100).reshape(10,10) > 0.7), fill_value=-999, hard_mask=True) self.marray._optinfo['memo'] = "Some line of text" self.tseries = ts.time_series(self.marray, start_date=ts.now('D')) self.file = tempfile.mktemp(".hdf5") self.fileh = tables.openFile(self.file,'a') self.populate()
def __init__(self, *args, **kwds): TestCase.__init__(self, *args, **kwds) self.marray = ma.array( np.random.rand(100).reshape(10, 10), mask=(np.random.rand(100).reshape(10, 10) > 0.7), fill_value=-999, hard_mask=True) self.marray._optinfo['memo'] = "Some line of text" self.tseries = ts.time_series(self.marray, start_date=ts.now('D')) self.file = tempfile.mktemp(".hdf5") self.fileh = tables.openFile(self.file, 'a') self.populate()
def __init__(self, *args, **kwds): TestCase.__init__(self, *args, **kwds) series = ts.time_series(zip(np.random.rand(10), np.arange(10)), start_date=ts.now('M'), dtype=[('a',float),('b',int)]) series.mask[0] = (0,1) series.mask[-1] = (1,0) self.tseries = series self.marray = series._series self.file = tempfile.mktemp(".hdf5") self.h5file = tables.openFile(self.file,'a') self.populate()
def test_ontimeseries(self): "Test the moving functions on a 1D TimeSeries" data = ts.time_series(self.maskeddata, start_date=ts.now("D")) for Mfunc, Nfunc in self.func_pairs: for k in [3, 4, 5]: result = Mfunc(data, k) self.failUnless(isinstance(result, MaskedArray)) for x in range(len(data) - k + 1): if result[x + k - 1] is not ma.masked: assert_almost_equal(np.asarray(result[x + k - 1]), np.asarray(Nfunc(data[x : x + k]))) result_mask = np.array([1] * (k - 1) + [0] * (len(data) - k + 1)) result_mask[10 : 10 + k] = 1 assert_equal(result._mask, result_mask) assert_equal(result._dates, data._dates)
def test_ontimeseries(self): "Test the moving functions on a 1D TimeSeries" data = ts.time_series(self.maskeddata, start_date=ts.now('D')) for Mfunc, Nfunc in self.func_pairs: for k in [3, 4, 5]: result = Mfunc(data, k) self.failUnless(isinstance(result, MaskedArray)) for x in range(len(data) - k + 1): if result[x + k - 1] is not ma.masked: assert_almost_equal(np.asarray(result[x + k - 1]), np.asarray(Nfunc(data[x:x + k]))) result_mask = np.array([1] * (k - 1) + [0] * (len(data) - k + 1)) result_mask[10:10 + k] = 1 assert_equal(result._mask, result_mask) assert_equal(result._dates, data._dates)
def setUp(self): "Initializes" ndtype = [('lin',float),('rand',float)] dlin = np.linspace(0,10,120) drnd = np.random.rand(120) data = np.array(zip(dlin, drnd), dtype=ndtype) dates = ts.date_array(start_date=ts.now('M')-120, length=120, freq='M') enso = ENSOIndicator(np.random.rand(120) + np.linspace(-1,1,120), dates=dates, thresholds=(-0.5,0.5), full_year='False', refseason='NDH', minsize=5) cdat = data.view(ClimateRecords) cdat._dates = dates cdat.ensoindicator = enso self.dlin = dlin self.cdat=cdat self.enso=enso
def tests_onmultitimeseries(self): "Test cmov_average on a nD TimeSeries." maskeddata = MaskedArray(np.random.random(75).reshape(25, 3)) maskeddata[10] = masked data = ts.time_series(maskeddata, start_date=ts.now("D")) for width in [3, 5, 7]: k = (width - 1) / 2 ravg = mf.cmov_average(data, width) self.failUnless(isinstance(ravg, MaskedArray)) #!!!: __getitem__ used to return a TimeSeries, now returns an array # assert_almost_equal(ravg[18]._series.squeeze(), # data[18-k:18+k+1]._series.mean(0)) assert_almost_equal(ravg[18].squeeze(), data[18 - k : 18 + k + 1]._series.mean(0)) m = np.zeros(data.shape, bool) m[:k] = m[-k:] = m[10 - k : 10 + k + 1] = True assert_equal(ravg._mask, m) assert_equal(ravg._dates, data._dates)
def tests_onmultitimeseries(self): "Test cmov_average on a nD TimeSeries." maskeddata = MaskedArray(np.random.random(75).reshape(25, 3)) maskeddata[10] = masked data = ts.time_series(maskeddata, start_date=ts.now('D')) for width in [3, 5, 7]: k = (width - 1) / 2 ravg = mf.cmov_average(data, width) self.failUnless(isinstance(ravg, MaskedArray)) #!!!: __getitem__ used to return a TimeSeries, now returns an array # assert_almost_equal(ravg[18]._series.squeeze(), # data[18-k:18+k+1]._series.mean(0)) assert_almost_equal(ravg[18].squeeze(), data[18 - k:18 + k + 1]._series.mean(0)) m = np.zeros(data.shape, bool) m[:k] = m[-k:] = m[10 - k:10 + k + 1] = True assert_equal(ravg._mask, m) assert_equal(ravg._dates, data._dates)
def setUp(self): "Initializes" ndtype = [('lin', float), ('rand', float)] dlin = np.linspace(0, 10, 120) drnd = np.random.rand(120) data = np.array(zip(dlin, drnd), dtype=ndtype) dates = ts.date_array(start_date=ts.now('M') - 120, length=120, freq='M') enso = ENSOIndicator(np.random.rand(120) + np.linspace(-1, 1, 120), dates=dates, thresholds=(-0.5, 0.5), full_year='False', refseason='NDH', minsize=5) cdat = data.view(ClimateRecords) cdat._dates = dates cdat.ensoindicator = enso self.dlin = dlin self.cdat = cdat self.enso = enso
import numpy as np import matplotlib.pyplot as plt import scikits.timeseries as ts import scikits.timeseries.lib.plotlib as tpl # generate some random data num_points = 12 data = np.cumprod(1 + np.random.normal(0, 1, num_points) / 100) series = ts.time_series(data, start_date=ts.now('d') - num_points) fig = tpl.tsfigure() fsp = fig.add_tsplot(111) fsp.tsplot(series, '-') fsp.set_xlim(int(series.start_date), int(series.end_date)) fsp.set_title('%i days' % num_points) plt.show()
def load_usgs_flows(site_no, cfgdict=usgs_config): """ Downloads hydrological data from the USGS site. Parameters ---------- site_no : str 2- to 15-digit identification number of the site whose information must be downloaded. netfile : {string}, optional URL of the USGS flow gage site. By default, the value is read from the configuration file. begin_date : {string}, optional First date to be retrieved. By default, the value is read from the configuration file. end_date : {None, string}, optional Last date to be retrieved. If None, uses the current date. datadir : {None, string}, optional Directory where to store the output. If None, uses the current directory. commentchar : {string}, optional Character corresponding to a comment. headerlines : {int}, optional Number of uncommented lines to skip from the beginning of the file. archive : {None, string}, optional Name of the ZIP archive where to read pre-stored data or when to store data newly retrieved. The default is read from the configuration file. Notes ----- The list of data codes valid for the ``data_type`` parameters are available on the `USGS site <http://waterdata.usgs.gov/nwis/pmcodes/pmcodes?pm_group=All+--+include+all+parameter+groups&pm_search=&format=html_table&show=parameter_group_nm&show=parameter_nm>`_ """ # Force the site_no to a 0-padded, 8-character string site_no = "%08i" % int(site_no) #data_type = cfgdict.get('data_type', '00060') data_type = '00060' data_letter = data_dict[data_type] usgsarchv = _check_archive(cfgdict) archfname = "%s%sD" % (data_letter, site_no) # try: zipf = zipfile.ZipFile(usgsarchv, 'r') series = cPickle.loads(zipf.read(archfname)) except IOError: zipf = zipfile.ZipFile(usgsarchv, 'w') except KeyError: zipf = zipfile.ZipFile(usgsarchv, 'a') else: if series.size > 0: return series else: zipf = zipfile.ZipFile(usgsarchv, 'a') # options = dict(usgs_site=cfgdict['netfile'], begin_date=cfgdict['begin_date'], data_type=data_type, site_no=site_no) end_date = cfgdict.get('end_date', None) if end_date is None: end_date = ts.now('D').strftime("%Y-%m-%d") options['end_date'] = end_date commd = "%(usgs_site)s/dv?format=rdb&cb_%(data_type)s=on&" + \ "begin_date=%(begin_date)s&end_date=%(end_date)s&" + \ "site_no=%(site_no)s" datadir = cfgdict.get('datadir', os.getcwd()) # We can't use np.lib._datasource.DataSource, the downloaded file has always # the same name and would be cached. sourcedir = np.lib._datasource.DataSource(datadir) dfile = urllib.urlopen(commd % options) # headers = int(cfgdict['headerlines']) # (datelist, datalist) = ([], []) for line in dfile.readlines(): line = line.strip().split("\t") if (not line) or (line[0][0] == '#'): continue try: datalist.append(line[3]) except IndexError: continue else: datelist.append(line[2]) series = ts.time_series( [float(_) for _ in datalist[headers:]], dates=[ts.Date('D', _) for _ in datelist[headers:]], freq='D') # zipf.writestr(archfname, cPickle.dumps(series)) zipf.close() return series
def load_usgs_flows(site_no, cfgdict=usgs_config): """ Downloads hydrological data from the USGS site. Parameters ---------- site_no : str 2- to 15-digit identification number of the site whose information must be downloaded. netfile : {string}, optional URL of the USGS flow gage site. By default, the value is read from the configuration file. begin_date : {string}, optional First date to be retrieved. By default, the value is read from the configuration file. end_date : {None, string}, optional Last date to be retrieved. If None, uses the current date. datadir : {None, string}, optional Directory where to store the output. If None, uses the current directory. commentchar : {string}, optional Character corresponding to a comment. headerlines : {int}, optional Number of uncommented lines to skip from the beginning of the file. archive : {None, string}, optional Name of the ZIP archive where to read pre-stored data or when to store data newly retrieved. The default is read from the configuration file. Notes ----- The list of data codes valid for the ``data_type`` parameters are available on the `USGS site <http://waterdata.usgs.gov/nwis/pmcodes/pmcodes?pm_group=All+--+include+all+parameter+groups&pm_search=&format=html_table&show=parameter_group_nm&show=parameter_nm>`_ """ # Force the site_no to a 0-padded, 8-character string site_no = "%08i" % int(site_no) #data_type = cfgdict.get('data_type', '00060') data_type = '00060' data_letter = data_dict[data_type] usgsarchv = _check_archive(cfgdict) archfname = "%s%sD" % (data_letter, site_no) # try: zipf = zipfile.ZipFile(usgsarchv, 'r') series = cPickle.loads(zipf.read(archfname)) except IOError: zipf = zipfile.ZipFile(usgsarchv, 'w') except KeyError: zipf = zipfile.ZipFile(usgsarchv, 'a') else: if series.size > 0: return series else: zipf = zipfile.ZipFile(usgsarchv, 'a') # options = dict(usgs_site=cfgdict['netfile'], begin_date=cfgdict['begin_date'], data_type=data_type, site_no= site_no) end_date = cfgdict.get('end_date', None) if end_date is None: end_date = ts.now('D').strftime("%Y-%m-%d") options['end_date'] = end_date commd = "%(usgs_site)s/dv?format=rdb&cb_%(data_type)s=on&" + \ "begin_date=%(begin_date)s&end_date=%(end_date)s&" + \ "site_no=%(site_no)s" datadir = cfgdict.get('datadir', os.getcwd()) # We can't use np.lib._datasource.DataSource, the downloaded file has always # the same name and would be cached. sourcedir = np.lib._datasource.DataSource(datadir) dfile = urllib.urlopen(commd % options) # headers = int(cfgdict['headerlines']) # (datelist, datalist) = ([], []) for line in dfile.readlines(): line = line.strip().split("\t") if (not line) or (line[0][0] == '#'): continue try: datalist.append(line[3]) except IndexError: continue else: datelist.append(line[2]) series = ts.time_series([float(_) for _ in datalist[headers:]], dates=[ts.Date('D', _) for _ in datelist[headers:]], freq='D') # zipf.writestr(archfname, cPickle.dumps(series)) zipf.close() return series
def filterMngsByDate(mngs, date = 1): date = ts.now('m') - date def _filtermng(mng, date): return len(mng.dates[mng.dates>date]) return [i for i in mngs if _filtermng(i[1], date)]
if hasattr(rand,generator): f = getattr(rand,generator) dd = f(**params) ## Add other distributions here else: raise TypeError, 'Unknown generator' except TypeError, exc: logging.error('%s generator - %s',rq['Source'],exc.args[0]) except: raise if s['FREQ']!='0': data = ts.time_series(dd, freq=s['FREQ'], dates=dr) if s['NAN']: t=ts.now(data.freqstr) if t<data.end_date: da = ts.date_array(start_date=t,end_date=data.end_date) data[da]=np.nan rx[kw['NAME']]=Timeseries(data=data,name=name) else: # for a vector print type(dd),dd.shape xx = dd.reshape((1,-1)) print type(xx),xx.shape rx[kw['NAME']]=np.array(dd) return rx # random://normal/loc=10,scale=.2~:2012-12-31~2007-01-01~M?name=UNI if __name__=="__main__": parse_instrument('NAME=PIPPO')
import numpy as np import matplotlib.pyplot as plt import scikits.timeseries as ts import scikits.timeseries.lib.plotlib as tpl # generate some random data num_points = 250 data = np.cumprod(1 + np.random.normal(0, 1, num_points)/100) series = ts.time_series(data, start_date=ts.now('d')-num_points) fig = tpl.tsfigure() fsp = fig.add_tsplot(111) fsp.tsplot(series, '-') fsp.set_xlim(int(series.start_date), int(series.end_date)) fsp.set_title('%i days' % num_points) plt.show()
def turningp(self,tsl,D,V=0.0,invert=False): """Turning Point - fill a series with a value from a turning point :param tsl: the input time-series :type tsl: a time-series :param D: a date specification :type D: a string representing a date (YYYY for A, YYYYMM for M, YYYYMMDD for D) :param V: a value (default 0.0) :type V: float :return: the modified time-series :rtype: a time-series :Example: dstream://Datastream/1.0$M_LIMIT?name=SOMEONE&proc=turningp(201101) dstream://Datastream/0.0$M_LIMIT?name=SOMEZERO&proc=turningp(201101,1.0) """ freq = tsl._data.freqstr[0] if re.match('^today$',D,re.I): _tp = ts.now(freq) else: if freq == 'A': _Y = int(D[0:4]) _tp = ts.Date(freq=freq,year=_Y) elif freq == 'M': _Y = int(D[0:4]) _M = int(D[4:6]) _tp = ts.Date(freq=freq,year=_Y,month=_M) elif freq == 'Q': _Y = int(D[0:4]) _Q = int(D[5:6]) _tp = ts.Date(freq=freq,year=_Y,quarter=_Q) elif freq == 'D': _Y = int(D[0:4]) _M = int(D[4:6]) _D = int(D[6:8]) _tp = ts.Date(freq=freq,year=_Y,month=_M,day=_D) else: raise OperationError, "turningp" print "TURNINGP DATE",_tp if re.match('^NAN$',V,re.I): _V=np.nan else: _V = float(V) _t1 = ts.time_series(tsl._data,copy=True) _t1.fill(0.0) if invert: _tpd = ts.date_array(start_date=_t1.start_date,end_date=_tp) else: _tpd = ts.date_array(start_date=_tp,end_date=_t1.end_date) _t1[_tpd]=1.0 _t = tsl._data * _t1 _t2 = ts.time_series(tsl._data,copy=True) _t2.fill(_V) if invert: _tpd = ts.date_array(start_date=_t2.start_date,end_date=_tp) else: _tpd = ts.date_array(start_date=_tp,end_date=_t2.end_date) _t2[_tpd]=0.0 _tx = _t + _t2 tsl._data = _tx return tsl
def countCrossOver(self, nom = None): if nom == None: return len(self.crossRecord) else: temp = self.getCrossOverDate() return len([i for i in (temp.dates > (ts.now('m') - nom)) if i])