mirror of
				https://github.com/bspeice/metrik
				synced 2025-11-04 02:10:43 -05:00 
			
		
		
		
	Add Tradeking functionality
Yet to be integrated with the Equities flow, hold your horses.
This commit is contained in:
		
							
								
								
									
										7
									
								
								.idea/inspectionProfiles/Project_Default.xml
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										7
									
								
								.idea/inspectionProfiles/Project_Default.xml
									
									
									
										generated
									
									
									
								
							@ -24,6 +24,13 @@
 | 
				
			|||||||
        </value>
 | 
					        </value>
 | 
				
			||||||
      </option>
 | 
					      </option>
 | 
				
			||||||
    </inspection_tool>
 | 
					    </inspection_tool>
 | 
				
			||||||
 | 
					    <inspection_tool class="PyShadowingBuiltinsInspection" enabled="true" level="WEAK WARNING" enabled_by_default="true">
 | 
				
			||||||
 | 
					      <option name="ignoredNames">
 | 
				
			||||||
 | 
					        <list>
 | 
				
			||||||
 | 
					          <option value="format" />
 | 
				
			||||||
 | 
					        </list>
 | 
				
			||||||
 | 
					      </option>
 | 
				
			||||||
 | 
					    </inspection_tool>
 | 
				
			||||||
    <inspection_tool class="PyUnresolvedReferencesInspection" enabled="false" level="WARNING" enabled_by_default="false">
 | 
					    <inspection_tool class="PyUnresolvedReferencesInspection" enabled="false" level="WARNING" enabled_by_default="false">
 | 
				
			||||||
      <option name="ignoredIdentifiers">
 | 
					      <option name="ignoredIdentifiers">
 | 
				
			||||||
        <list>
 | 
					        <list>
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										
											BIN
										
									
								
								.metrik.enc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								.metrik.enc
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							@ -10,5 +10,8 @@ services:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
before_install:
 | 
					before_install:
 | 
				
			||||||
  - export TZ=America/New_York
 | 
					  - export TZ=America/New_York
 | 
				
			||||||
 | 
					  # Encrypted .metrik.enc file contains credentials for services that are behind OAuth, etc.
 | 
				
			||||||
 | 
					  - openssl aes-256-cbc -K $encrypted_4cca49abdb96_key -iv $encrypted_4cca49abdb96_iv -in .metrik.enc -out ~\/.metrik -d
 | 
				
			||||||
 | 
					
 | 
				
			||||||
install: pip install -r requirements.txt
 | 
					install: pip install -r requirements.txt
 | 
				
			||||||
script: python setup.py test
 | 
					script: python setup.py test
 | 
				
			||||||
@ -1,2 +1,2 @@
 | 
				
			|||||||
__version__ = '0.2.3'
 | 
					__version__ = '0.3.0'
 | 
				
			||||||
__release__ = __version__
 | 
					__release__ = __version__
 | 
				
			||||||
							
								
								
									
										82
									
								
								metrik/tasks/tradeking.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										82
									
								
								metrik/tasks/tradeking.py
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,82 @@
 | 
				
			|||||||
 | 
					import requests
 | 
				
			||||||
 | 
					from requests_oauthlib import OAuth1Session
 | 
				
			||||||
 | 
					from luigi.parameter import DateParameter, Parameter
 | 
				
			||||||
 | 
					from datetime import timedelta
 | 
				
			||||||
 | 
					from dateutil.parser import parse
 | 
				
			||||||
 | 
					import logging
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from metrik.tasks.base import MongoCreateTask, MongoRateLimit
 | 
				
			||||||
 | 
					from metrik.conf import get_config
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class TradekingApi(object):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    format_json = '.json'
 | 
				
			||||||
 | 
					    format_xml = '.xml'
 | 
				
			||||||
 | 
					    root_url = 'https://api.tradeking.com/v1/'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def __init__(self):
 | 
				
			||||||
 | 
					        config = get_config()
 | 
				
			||||||
 | 
					        self.session = OAuth1Session(
 | 
				
			||||||
 | 
					            client_key=config.get('tradeking', 'consumer_key'),
 | 
				
			||||||
 | 
					            client_secret=config.get('tradeking', 'consumer_secret'),
 | 
				
			||||||
 | 
					            resource_owner_key=config.get('tradeking', 'oauth_token'),
 | 
				
			||||||
 | 
					            resource_owner_secret=config.get('tradeking', 'oauth_token_secret')
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def api_request(self, url, params=None, format=format_json, **kwargs):
 | 
				
			||||||
 | 
					        full_url = self.root_url + url + format
 | 
				
			||||||
 | 
					        return self.session.get(full_url, params=params, **kwargs)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Tradeking1mTimesales(MongoCreateTask):
 | 
				
			||||||
 | 
					    # While this is marked as an idempotent task, it only goes back about
 | 
				
			||||||
 | 
					    # a week or so. Be careful.
 | 
				
			||||||
 | 
					    present = DateParameter()
 | 
				
			||||||
 | 
					    symbol = Parameter()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def acquire_lock(self, service, limit, interval, max_tries=5, backoff=.5):
 | 
				
			||||||
 | 
					        return super(Tradeking1mTimesales, self).acquire_lock(
 | 
				
			||||||
 | 
					            'tradeking', 60, timedelta(minutes=1)
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @staticmethod
 | 
				
			||||||
 | 
					    def retrieve_data(present, symbol):
 | 
				
			||||||
 | 
					        ratelimit = MongoRateLimit()
 | 
				
			||||||
 | 
					        tradeking = TradekingApi()
 | 
				
			||||||
 | 
					        did_acquire = ratelimit.acquire_lock(
 | 
				
			||||||
 | 
					            service='tradeking',
 | 
				
			||||||
 | 
					            limit=60,
 | 
				
			||||||
 | 
					            interval=timedelta(minutes=1)
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        if did_acquire:
 | 
				
			||||||
 | 
					            json_data = tradeking.api_request('market/timesales', {
 | 
				
			||||||
 | 
					                'symbols': symbol,
 | 
				
			||||||
 | 
					                'interval': '1min',
 | 
				
			||||||
 | 
					                'startdate': present.strftime('%Y-%m-%d'),
 | 
				
			||||||
 | 
					                'enddate': present.strftime('%Y-%m-%d')
 | 
				
			||||||
 | 
					            }).json()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            quotes = json_data['response']['quotes']['quote']
 | 
				
			||||||
 | 
					            def format_quote(quote):
 | 
				
			||||||
 | 
					                return {
 | 
				
			||||||
 | 
					                    'last': float(quote['last']),
 | 
				
			||||||
 | 
					                    'lo': float(quote['lo']),
 | 
				
			||||||
 | 
					                    'vl': int(quote['vl']),
 | 
				
			||||||
 | 
					                    'datetime': parse(quote['datetime']),
 | 
				
			||||||
 | 
					                    'incr_vl': int(quote['incr_vl']),
 | 
				
			||||||
 | 
					                    'hi': float(quote['hi']),
 | 
				
			||||||
 | 
					                    'timestamp': parse(quote['timestamp']),
 | 
				
			||||||
 | 
					                    'date': parse(quote['date']).date(),
 | 
				
			||||||
 | 
					                    'opn': float(quote['opn'])
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            quotes_typed = [format_quote(q) for q in quotes]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            return {
 | 
				
			||||||
 | 
					                'symbol': symbol,
 | 
				
			||||||
 | 
					                'quotes': quotes_typed
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            logging.error('Unable to acquire lock for Tradeking ticker {}'
 | 
				
			||||||
 | 
					                          .format(symbol))
 | 
				
			||||||
 | 
					            return {}
 | 
				
			||||||
							
								
								
									
										3
									
								
								setup.py
									
									
									
									
									
								
							
							
						
						
									
										3
									
								
								setup.py
									
									
									
									
									
								
							@ -26,7 +26,8 @@ setup(
 | 
				
			|||||||
    ],
 | 
					    ],
 | 
				
			||||||
    tests_require=[
 | 
					    tests_require=[
 | 
				
			||||||
        'pytest',
 | 
					        'pytest',
 | 
				
			||||||
        'pytest-catchlog'
 | 
					        'pytest-catchlog',
 | 
				
			||||||
 | 
					        'pandas-datareader'
 | 
				
			||||||
    ],
 | 
					    ],
 | 
				
			||||||
    entry_points={
 | 
					    entry_points={
 | 
				
			||||||
        'console_scripts': [
 | 
					        'console_scripts': [
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										37
									
								
								test/tasks/test_tradeking.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								test/tasks/test_tradeking.py
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,37 @@
 | 
				
			|||||||
 | 
					from unittest import TestCase
 | 
				
			||||||
 | 
					from datetime import datetime
 | 
				
			||||||
 | 
					from pandas_datareader.data import get_data_yahoo
 | 
				
			||||||
 | 
					from numpy.testing import assert_allclose
 | 
				
			||||||
 | 
					import pytest
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from metrik.tasks.tradeking import Tradeking1mTimesales
 | 
				
			||||||
 | 
					from metrik.trading_days import TradingDay
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@pytest.mark.parametrize('ticker', [
 | 
				
			||||||
 | 
					    'AAPL', 'GOOG', 'SPY', 'REGN', 'SWHC', 'BAC', 'NVCR'
 | 
				
			||||||
 | 
					])
 | 
				
			||||||
 | 
					def test_returns_verifiable(ticker):
 | 
				
			||||||
 | 
					    # Test that the quotes line up with data off of Yahoo
 | 
				
			||||||
 | 
					    now = datetime.now()
 | 
				
			||||||
 | 
					    prior_day = now - TradingDay(1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    quotes = Tradeking1mTimesales.retrieve_data(prior_day, ticker)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    yahoo_ohlc = map(tuple, get_data_yahoo(ticker, prior_day, prior_day)[
 | 
				
			||||||
 | 
					        ['Open', 'High', 'Low', 'Close']
 | 
				
			||||||
 | 
					    ].values)[0]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    open = high = close = 0
 | 
				
			||||||
 | 
					    low = 999999
 | 
				
			||||||
 | 
					    for index, quote in enumerate(quotes['quotes']):
 | 
				
			||||||
 | 
					        if index == 0:
 | 
				
			||||||
 | 
					            open = quote['opn']
 | 
				
			||||||
 | 
					        if index == len(quotes['quotes']) - 1:
 | 
				
			||||||
 | 
					            close = quote['last']
 | 
				
			||||||
 | 
					        high = max(high, quote['hi'])
 | 
				
			||||||
 | 
					        low = min(low, quote['lo'])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    tradeking_ohlc = (open, high, low, close)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    assert_allclose(tradeking_ohlc, yahoo_ohlc, rtol=1e-3)
 | 
				
			||||||
		Reference in New Issue
	
	Block a user