In [86]:
%matplotlib inline
from lime import lime
In [44]:
from datetime import timedelta
class LimeInvalidTicker(Exception):
'''
An Exception for handling invalid tickers
'''
def __init__(self):
self.msg = ('Lime was not able to find that ticker symbol on Netfonds.'
'Please check your ticker and try again.')
def __str__(self):
return repr(self.msg)
class LimeInvalidQuery(Exception):
'''
An Exception for handling invalid requests
###Parameters
* url -- string, should be self._url used to access NetFonds
'''
def __init__(self, url):
self.url = url
self.msg = ('Lime was not able to contact Netfonds, based'
' on the information you provided.'
'Please check your request and try again.')
def __str__(self):
return repr("Invalid Query:{}:\n{}".format(self.msg, self.url))
class LimeInvalidDate(Exception):
'''
An Exception for handling invalid dates for requests Invalid
###Parameters
* start -- datetime object, should be self.start_date
* end -- datetime object, should be self.end_date
'''
def __init__(self, start, end):
self.msg = self.check_date(start, end)
self.start = start
self.end = end
def check_date(self):
'''
returns the appropriate error message based
on the provided dates.
'''
if (self.end - self.start) > timedelta(21):
self.msg = ('Date range is greater than 21 days.'
'Data does not exist on NetFonds beyond 21 days.\n'
'Please reconstruct your query and try again.')
if self.start > self.end:
self.msg = ('The Start Date is greater than the End Date.\n'
'You most likely reversed the begining_date and end_date.')
def __str__(self):
return repr("Invalid Date:{}:\n{}".format(self.msg, self.date))
In [ ]:
import datetime
from datetime import timedelta
from pandas import DataFrame, concat, date_range, read_csv
from .exceptions import LimeInvalidQuery, LimeInvalidDate, LimeInvalidTicker
class Lime:
'''
A simple API for extracting stock tick data.
###Parameters
* start_date -- datetime, date beginning the retrieval window
* end_date -- datetime, date ending the retrieval window
* exchange -- string ( optional ), ticker's exchange: ['Nasdaq', 'Nyse', 'Amex']
* ticker -- string ( optional ), stock ticker symbol. With or with out
Netfonds exchange extension.
'''
def __init__(self, start_date, end_date=None, exchange=None, ticker=None):
self.start_date = self.initialize_date(start_date)
self.end_date = self.initialize_date(end_date)
self.ticker = None
self._exchange = exchange
self._file_format = 'csv'
self._df = None
self._exchanges = {
'Nasdaq': '.O',
'Nyse': '.N',
'Amex': '.A'
}
self.exchange_extensions = ['O', 'N', 'A']
self._url = 'http://www.netfonds.no/quotes/tradedump.php'
self.uri = None
def get_exchange(self):
''' Returns the exchange chosen '''
return self._exchange
def get_df(self):
''' Gets the stored tick data '''
return self._df
def set_df(self, dataframe):
'''
Sets stored tick data
Parameters
* dataframe -- pandas.DataFrame()
'''
self._df = concat([self.get_df(), dataframe]) if self._df is None else dataframe
self.process_data()
def initialize_date(self, date):
'''
Returns parsed todays date, a parsed supplied date
###Parameters
* date -- datetime, date to be parsed
'''
if not date:
date = datetime.date.today()
return self.date_parse(date)
def date_parse(self, date):
'''
Parses date to YYYY/MM/DD.
###Parameters
* date -- datetime, date to be parsed
'''
return date.strftime('%Y%m%d')
def check_date(self, start, end):
'''
Checks whether supplied dates are acceptable.
###Parameters
* start -- datetime, date beginning the retrieval window
* end -- datetime, date ending the retrieval window
'''
if timedelta(0) > (end - start) > timedelta(21):
raise LimeInvalidDate(start, end)
return True
def format_ticker_with_exchange_extenstion(self):
self.ticker = "{}{}".format(self.ticker,
self._exchanges[self._exchange.title()])
return self.ticker
def validate_ticker_exchange_extenstion(self):
'''Checks if ticker has a valid exchange extension. '''
extension = self.ticker.split('.')[1]
if extension in self.exchange_extensions:
return True
return False
def check_ticker_exchange_extenstion(self):
'''
Check's whether the appropriate netfonds extension, ( '.N', '.O', '.A' ), has been added.
If it hasn't, but the ticker's exchange has, it adds the appropriate extension.
If neither have; it raises a LimeInvalidTicker exception.
'''
try:
self.validate_ticker_exchange_extenstion()
except IndexError:
if not self._exchange:
self.get_exchange_extension_from_ticker()
self.format_ticker_with_exchange_extenstion()
else:
raise LimeInvalidTicker()
return self.ticker
def get_exchange_extension_from_ticker(self):
'''
Loops through the three exchanges Netfonds supports, ( Nasdaq, NYSE, Amex),
and returns the correct exchange extension if it exists.
'''
for key in self._exchanges.keys():
self.ticker = "{}{}".format(self.ticker, self._exchanges[key])
self._get_tick_data()
if self._df is not None and (len(self._df.columns) > 1):
self._exchange = key
self.format_ticker_with_exchange_extenstion()
return self._exchange
raise LimeInvalidTicker()
def set_start_end_dates(self, start, end=None):
'''
Parses and Prepares Start and End dates.
###Parameters
* start -- datetime
* end -- ( optional ) datetime, defaults to today's date
'''
self.start_date = self.date_parse(start)
self.end_date = self.date_parse(end) if end else self.get_date_today()
self.check_date(start, end)
def process_data(self):
'''
Cleans data after its retrieved from Netfonds
'''
df = self.get_df()
try:
df.time = df.time.apply(lambda x: datetime.datetime.strptime(x, '%Y%m%dT%H%M%S'))
df = df.set_index(df.time)
except AttributeError:
raise LimeInvalidQuery(self.uri)
def _get_tick_data(self):
'''
Retrieves tick data from Netfonds from a known ticker.
'''
self.uri = '{}?date={}&paper={}&csv_format={}'.format(self._url,
self.start_date,
self.ticker,
self._file_format)
self.set_df(read_csv(self.uri))
def get_trades(self, ticker, exchange=None):
'''
Gets the trades made for a ticker on a specified day.
###Parameters
* ticker -- string, stock ticker symbol
'''
if exchange:
self.exchange = exchange
self.ticker = ticker
self.check_ticker_exchange_extenstion()
self._get_tick_data()
return self.get_df()
def get_trade_history(self, ticker, start_date, end_date=None):
'''
Retrieves the trades made for a ticker from a range of days.
###Parameters
* ticker -- string, stock ticker symbol
* start_date -- datetime, starting date of retrieval window
* end_date -- datetime (optional), ending date of retrieval window.
defaults to today, if committed.
Note: Tick data only persist for 21 days on Netfonds. Any queries greater
than that window will raise a LimeInvalidQuery exception.
'''
self.ticker = ticker
self.set_start_end_dates(start_date, end_date)
for day in date_range(start=start_date, end=self.end_date, freq='B'):
self.start_date = self.date_parse(day)
self.set_df(self.get_trades(self.ticker))
return self.get_df()
In [79]:
start_date = datetime.datetime.today() - timedelta(days=5)
In [80]:
lime = Lime(start_date, exchange="Nasdaq")
In [83]:
AAPL_single_day = lime.get_trades('AAPL')
In [84]:
AAPL_single_day
Out[84]:
In [85]:
fig = plt.figure(figsize(18,4), dpi=1600)
AAPL_single_day.price.plot()
plt.title("Apple stock movements on: " + str(lime.start_date))
In [5]:
AAPL_many_days = lime.get_many(begining_date=datetime.date(2013,5,29), end_date=datetime.date(2013,6,18), ticker='AAPL')
In [6]:
AAPL_many_days
Out[6]:
In [53]:
fig = plt.figure(figsize(18,4), dpi=1600)
AAPL_many_days.price.plot()
plt.title('Apple price movements over the last 21 days')
savefig('Apple.png', bbox_inches=0)
In [7]:
goog = lime.get_many(begining_date=datetime.date(2013,5,29), end_date=datetime.date(2013,6,18), ticker='GOOG')
In [52]:
fig = plt.figure(figsize(18,4), dpi=1600)
goog.price.plot()
plt.title("Google's price movements over the last 21 days")
savefig('GOOG.png', bbox_inches=0)
In [20]:
import pandas
#df = pandas.merge(AAPL_many_days, goog, on='time', suffixes=('_AAPL', '_GOOG'))
plt.figure(figsize(18,8), dpi=1600)
plt.subplot(212)
df.price_AAPL.plot()
legend(loc='best')
plt.subplot(211)
df.price_GOOG.plot(color='g')
plt.title("Apple's and Google's price movements"); legend(loc='best')
Out[20]:
In [48]:
!git add lime_demo.ipynb
In [50]:
!git commit
In [ ]: