mirror of
https://github.com/bspeice/metrik
synced 2024-11-05 06:58:12 -05:00
Add initial State Street holdings functionality
This commit is contained in:
parent
52049b7d0f
commit
d48649c565
@ -4,13 +4,11 @@
|
|||||||
<inspection_tool class="PyCompatibilityInspection" enabled="true" level="WARNING" enabled_by_default="true">
|
<inspection_tool class="PyCompatibilityInspection" enabled="true" level="WARNING" enabled_by_default="true">
|
||||||
<option name="ourVersions">
|
<option name="ourVersions">
|
||||||
<value>
|
<value>
|
||||||
<list size="6">
|
<list size="4">
|
||||||
<item index="0" class="java.lang.String" itemvalue="2.7" />
|
<item index="0" class="java.lang.String" itemvalue="2.7" />
|
||||||
<item index="1" class="java.lang.String" itemvalue="3.1" />
|
<item index="1" class="java.lang.String" itemvalue="3.3" />
|
||||||
<item index="2" class="java.lang.String" itemvalue="3.2" />
|
<item index="2" class="java.lang.String" itemvalue="3.4" />
|
||||||
<item index="3" class="java.lang.String" itemvalue="3.3" />
|
<item index="3" class="java.lang.String" itemvalue="3.5" />
|
||||||
<item index="4" class="java.lang.String" itemvalue="3.4" />
|
|
||||||
<item index="5" class="java.lang.String" itemvalue="3.5" />
|
|
||||||
</list>
|
</list>
|
||||||
</value>
|
</value>
|
||||||
</option>
|
</option>
|
||||||
|
44
metrik/tasks/state_street.py
Normal file
44
metrik/tasks/state_street.py
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
import requests
|
||||||
|
from luigi.parameter import Parameter
|
||||||
|
import pandas as pd
|
||||||
|
|
||||||
|
from metrik.tasks.base import MongoNoBackCreateTask
|
||||||
|
|
||||||
|
|
||||||
|
class StateStreetHoldings(MongoNoBackCreateTask):
|
||||||
|
ticker = Parameter() # type: str
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def retrieve_data(ticker, current_datetime, live):
|
||||||
|
# TODO: Actually make this static
|
||||||
|
base_url = 'https://www.spdrs.com/site-content/xls/{fund}_All_Holdings.xls'
|
||||||
|
fund_url = base_url.format(fund=ticker)
|
||||||
|
|
||||||
|
excel_content = pd.read_excel(fund_url, header=None)
|
||||||
|
|
||||||
|
# The actual stuff we care about is arranged in tabular format, thus
|
||||||
|
# we actually want to get the rows where the far-right column is
|
||||||
|
# not null.
|
||||||
|
final_column_index = len(excel_content.columns) - 1
|
||||||
|
# And build a series of True/False for "We do want this row" and
|
||||||
|
# "we do not want this row" respectively
|
||||||
|
do_retain = excel_content[[final_column_index]].isnull() == False
|
||||||
|
retain_index = do_retain[do_retain[final_column_index] == True].index
|
||||||
|
|
||||||
|
# Actual content is in rows 2 onwards
|
||||||
|
holding_df = excel_content.ix[retain_index[1:]]
|
||||||
|
# Headers are in row 1
|
||||||
|
holding_df.columns = excel_content.ix[retain_index[0]]
|
||||||
|
|
||||||
|
# And also get the metadata that are in the rows prior to content
|
||||||
|
metadata = excel_content.ix[0:retain_index[0]-1].dropna(axis=1)
|
||||||
|
metadata_dict = {row[0].strip(':'): row[1]
|
||||||
|
for i, row in metadata.iterrows()}
|
||||||
|
|
||||||
|
return dict(
|
||||||
|
holdings=holding_df.to_dict(orient='record'),
|
||||||
|
**metadata_dict
|
||||||
|
)
|
||||||
|
|
||||||
|
def get_collection_name(self):
|
||||||
|
return 'state_street_holdings'
|
49
test/tasks/test_state_street.py
Normal file
49
test/tasks/test_state_street.py
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
# coding=utf-8
|
||||||
|
from unittest import TestCase
|
||||||
|
from datetime import datetime
|
||||||
|
|
||||||
|
from metrik.tasks.state_street import StateStreetHoldings
|
||||||
|
|
||||||
|
|
||||||
|
class StateStreetHoldingTest(TestCase):
|
||||||
|
def test_spy_holdings(self):
|
||||||
|
holdings_dict = StateStreetHoldings.retrieve_data(
|
||||||
|
'SPY', datetime.now(), True
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertEqual(holdings_dict['Ticker Symbol'], 'SPY')
|
||||||
|
self.assertEqual(holdings_dict['Fund Name'], u'SPDR® S&P 500® ETF')
|
||||||
|
self.assertGreaterEqual(len(holdings_dict['holdings']), 500)
|
||||||
|
# Long live AAPL
|
||||||
|
self.assertTrue(holdings_dict['holdings'][0]['Identifier'] == u'AAPL')
|
||||||
|
|
||||||
|
def test_sdy_holdings(self):
|
||||||
|
holdings_dict = StateStreetHoldings.retrieve_data(
|
||||||
|
'SDY', datetime.now(), True
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertEqual(holdings_dict['Ticker Symbol'], 'SDY')
|
||||||
|
self.assertEqual(holdings_dict['Fund Name'], u'SPDR® S&P® Dividend ETF')
|
||||||
|
self.assertTrue(holdings_dict['holdings'][0]['Identifier'] == 'HCP')
|
||||||
|
|
||||||
|
def test_spyd_holdings(self):
|
||||||
|
holdings_dict = StateStreetHoldings.retrieve_data(
|
||||||
|
'SPYD', datetime.now(), True
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertEqual(holdings_dict['Ticker Symbol'], 'SPYD')
|
||||||
|
self.assertEqual(holdings_dict['Fund Name'], u'SPDR® S&P® 500 High Dividend ETF')
|
||||||
|
|
||||||
|
def test_r3k_holdings(self):
|
||||||
|
holdings_dict = StateStreetHoldings.retrieve_data(
|
||||||
|
'THRK', datetime.now(), True
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertEqual(holdings_dict['Ticker Symbol'], 'THRK')
|
||||||
|
self.assertEqual(holdings_dict['Fund Name'], u'SPDR Russell 3000® ETF')
|
||||||
|
# Interesting story: the fund is not required to actually invest in all
|
||||||
|
# 3000 Russell equities, but just seeks to track the index in general.
|
||||||
|
# That's why the test is against 2000, not 3000.
|
||||||
|
# This also means that we can't check lists of say iShares against this
|
||||||
|
# because they're not guaranteed to be consistent.
|
||||||
|
self.assertGreaterEqual(len(holdings_dict['holdings']), 2000)
|
Loading…
Reference in New Issue
Block a user