def test_get_fundamentals_unauth(): c = TDClient(authenticated=False) res = c.get_fundamentals("aapl") assert isinstance(res, Fundamental) assert res.symbol == "AAPL" assert res.peRatio is not None assert res.marketCap is not None
def test_find_instrument_unauth(): c = TDClient(authenticated=False) res = c.find_instrument("lyft.*") # Expecting LYFT assert len(res.keys()) == 1 assert "LYFT" in res.keys() assert isinstance(res["LYFT"], Instrument) assert res["LYFT"].symbol == "LYFT" assert res["LYFT"].exchange == "NASDAQ"
def test_get_history(): c = TDClient(authenticated=False) with pytest.raises(InvalidArgument): c.get_history("aapl", start_dt=datetime(2019, 1, 31), end_dt=datetime(2019, 1, 1)) with pytest.raises(InvalidArgument): c.get_history("aapl") with pytest.raises(InvalidArgument): c.get_history( "aapl", start_dt=datetime(2019, 1, 1), end_dt=datetime(2019, 1, 31), freq="5d", ) # Ensure that we don't need to pass a end_dt (defaults to datetime.today()) with mock.patch.object(TDClient, "_get_with_retry") as m: m.return_value.json.return_value = { "empty": False, "candles": ["1", "2"] } out = c.get_history("aapl", start_dt=datetime(2019, 1, 1)) m.assert_called_once() assert out == ["1", "2"]
def test_get_option_chain(): c = TDClient(authenticated=False) sym = "AAPL" expiry = "2019-08-23" with pytest.raises(InvalidArgument): c.get_option_chain() with pytest.raises(InvalidArgument): c.get_option_chain(sym) with pytest.raises(InvalidArgument): c.get_option_chain(expiry=expiry) with open("tests/data/aapl_one_expiry.json", "r") as json_file: chain_resp = json.load(json_file) responses.add( responses.GET, Urls.option_chain + (f"?apikey={apikey}&symbol={sym}" f"&strategy=SINGLE&fromDate={expiry}&toDate={expiry}"), json=chain_resp, status=200, ) chain = c.get_option_chain(sym, expiry) expected_strikes = list(range(130, 150, 5)) expected_strikes.extend([x / 10 for x in range(1500, 2501, 25)]) assert isinstance(chain, OptionChain) assert len(chain._calls) == len(expected_strikes) assert len(chain._puts) == len(expected_strikes) for strike in expected_strikes: assert isinstance(chain.get(strike, "C"), Option) assert isinstance(chain.get(strike, "P"), Option) with pytest.raises(InvalidArgument): chain.get(200, "") with pytest.raises(InvalidArgument): chain.get(200, "call_option") vs = chain.get_vertical("C", 145, 150) assert isinstance(vs, VerticalSpread) assert isinstance(vs.long_option, Option) assert isinstance(vs.short_option, Option) assert vs.long_option.strikePrice == 145.0 assert vs.short_option.strikePrice == 150.0 s = chain.get_straddle(200) assert isinstance(s, Straddle) assert isinstance(s.call_option, Option) assert isinstance(s.put_option, Option) assert s.call_option.strikePrice == 200.0 assert s.put_option.strikePrice == 200.0 s = chain.get_strangle(200, 202.5) assert isinstance(s, Strangle) assert isinstance(s.call_option, Option) assert isinstance(s.put_option, Option) assert s.call_option.strikePrice == 200.0 assert s.put_option.strikePrice == 202.5
def test_access_token_refresh_fail(): c = TDClient(access_token="Invalid", refresh_token="Invalid", app_id="Invalid") responses.add(responses.GET, Urls.quote + f"?symbol=FB", json={}, status=401) with mock.patch.object(TDClient, "_update_access_token") as m: with pytest.raises(HTTPError): c.quote("FB") m.assert_called_once()
def test_get_fundamentals(): c = TDClient(authenticated=False) sym = "AAPL" responses.add( responses.GET, Urls.search + f"?apikey={apikey}&symbol={sym}&projection=fundamental", json=fundamental_resp(sym), status=200, ) res = c.get_fundamentals(sym.lower()) assert isinstance(res, Fundamental) assert res.symbol == sym assert res.peRatio == 18.15
def test_find_instrument(): c = TDClient(authenticated=False) # TD API accepts lowercase for the search endpoint sym = "lyf.*" responses.add( responses.GET, Urls.search + f"?apikey={apikey}&symbol={sym}&projection=symbol-regex", json=quote_resp("LYFT"), status=200, ) res = c.find_instrument(sym) assert len(res) == 1 assert isinstance(res["LYFT"], Instrument)
def test_quotes_unauth(): c = TDClient(authenticated=False) # Test Symbol not found with pytest.raises(SymbolNotFound): c.quotes(["No Dice", "None Here Too"]) # Test valid case res = c.quotes(["fb", "msft"]) assert len(res.keys()) == 2 assert "FB" in res.keys() assert "MSFT" in res.keys() validate_quote_response(res["FB"], "FB") validate_quote_response(res["MSFT"], "MSFT")
def test_get_history_unauth(): c = TDClient(authenticated=False) res = c.get_history("aapl", start_dt=datetime(2019, 1, 1), end_dt=datetime(2019, 1, 31)) assert len(res) == 21 assert len(res[0].keys()) == 6 keys = ["open", "high", "low", "close", "volume", "datetime"] for k in keys: assert k in res[0].keys() res = c.get_history("No Dice", start_dt=datetime(2019, 1, 1), end_dt=datetime(2019, 1, 31)) assert res is None
def test_quote_auth(): c = TDClient(access_token="Invalid", refresh_token="Invalid", app_id="Invalid") responses.add( responses.GET, Urls.quote + f"?symbol=FB", json={"FB": { "symbol": "FB" }}, status=200, ) res = c.quote("FB") assert isinstance(res, Quote) assert res.symbol == "FB"
def test_get_history_df_unauth(): import pandas as pd c = TDClient(authenticated=False) res = c.get_history_df("aapl", start_dt=datetime(2019, 1, 1), end_dt=datetime(2019, 1, 31)) assert isinstance(res, pd.DataFrame) assert res.shape == (21, 5) assert res.index.name == "datetime" keys = ["open", "high", "low", "close", "volume"] for k in res.columns: assert k in keys res = c.get_history_df("No Dice", start_dt=datetime(2019, 1, 1), end_dt=datetime(2019, 1, 31)) assert res is None
def test_auth_refresh(): c = TDClient(access_token="Invalid token") with mock.patch.object(TDClient, "_update_access_token", side_effect=c._update_access_token) as m: res = c.quote("AAPL") m.assert_called_once() assert isinstance(res, Quote) assert res.bidPrice is not None assert res.symbol == "AAPL" assert res.exchangeName == "NASD" with mock.patch.object(TDClient, "_update_access_token", side_effect=c._update_access_token) as m: res = c.quote("FB") m.assert_not_called() assert isinstance(res, Quote) assert res.bidPrice is not None assert res.symbol == "FB" assert res.exchangeName == "NASD"
def test_quote(): c = TDClient(authenticated=False) sym = "FB" responses.add( responses.GET, Urls.quote + f"?apikey={apikey}&symbol={sym}", json=quote_resp(sym), status=200, ) res = c.quote(sym) assert res.symbol == sym # Test the automatic upper casing res = c.quote("fb") assert res.symbol == sym responses.add( responses.GET, Urls.quote + f"?apikey={apikey}&symbol=NO DICE", json={}, status=200, ) with pytest.raises(SymbolNotFound): c.quote("No Dice")
def test_access_token_refresh_success(): c = TDClient(access_token="Invalid", refresh_token="Invalid", app_id="Invalid") responses.add(responses.GET, Urls.quote + f"?symbol=FB", json={}, status=401) responses.add( responses.GET, Urls.quote + f"?symbol=FB", json={"FB": { "symbol": "FB" }}, status=200, ) with mock.patch.object(TDClient, "_update_access_token") as m: res = c.quote("FB") assert isinstance(res, Quote) assert res.symbol == "FB" m.assert_called_once()
def test_get_option(): c = TDClient(authenticated=False) sym = "AAPL" expiry = "2019-08-23" strike = 200 with open("tests/data/aapl_200.json", "r") as json_file: chain_resp = json.load(json_file) responses.add( responses.GET, Urls.option_chain + (f"?apikey={apikey}&symbol={sym}" f"&contractType=CALL&strategy=SINGLE&strike=200" f"&fromDate={expiry}&toDate={expiry}"), json=chain_resp, status=200, ) opt = c.get_option(symbol=sym, expiry=expiry, right="C", strike=strike) assert isinstance(opt, Option) assert opt.strikePrice == 200.0 assert opt.putCall == "CALL" assert opt.lastTradingDay == 1566532800000 assert sym in opt.symbol responses.add( responses.GET, Urls.option_chain + (f"?apikey={apikey}&symbol={sym}" f"&contractType=PUT&strategy=SINGLE&strike=200" f"&fromDate={expiry}&toDate={expiry}"), json=chain_resp, status=200, ) opt = c.get_option(symbol=sym, expiry=expiry, right="P", strike=strike) assert isinstance(opt, Option) assert opt.strikePrice == 200.0 assert opt.putCall == "PUT" assert opt.lastTradingDay == 1566532800000 assert sym in opt.symbol with open("tests/data/no_dice.json", "r") as json_file: chain_resp = json.load(json_file) sym = "NO DICE" responses.add( responses.GET, Urls.option_chain + (f"?apikey={apikey}&symbol={sym}" f"&contractType=CALL&strategy=SINGLE&strike=200" f"&fromDate={expiry}&toDate={expiry}"), json=chain_resp, status=200, ) with pytest.raises(SymbolNotFound): c.get_option(symbol="NO DICE", expiry=expiry, right="C", strike=strike)
def test_get_intraday_history_df_unauth(): import pandas as pd c = TDClient(authenticated=False) res = c.get_history_df( "aapl", start_dt=datetime.today() - timedelta(4), end_dt=datetime.today(), freq="30min", ) assert isinstance(res, pd.DataFrame) assert res.shape[1] == 5 assert res.index.name == "datetime" keys = ["open", "high", "low", "close", "volume"] for k in res.columns: assert k in keys with pytest.raises(InvalidArgument): res = c.get_history_df( "AAPL", start_dt=datetime.today() - timedelta(60), end_dt=datetime.today() - timedelta(55), freq="30min", )
def test_get_expirations(): c = TDClient(authenticated=False) sym = "AAPL" with open("tests/data/aapl_all_exp_calls.json", "r") as json_file: chain_resp = json.load(json_file) responses.add( responses.GET, Urls.option_chain + (f"?apikey={apikey}&symbol={sym}" f"&contractType=CALL&strategy=SINGLE&range=NTM"), json=chain_resp, status=200, ) expiries = c.get_expirations(sym) expected = [ "2019-08-23", "2019-08-30", "2019-09-06", "2019-09-13", "2019-09-20", "2019-09-27", "2019-10-18", "2019-11-15", "2019-12-20", "2020-01-17", "2020-03-20", "2020-04-17", "2020-06-19", "2020-09-18", "2021-01-15", "2021-06-18", ] assert sorted(expiries) == sorted(expected)
def test_quote_unauth(): c = TDClient(authenticated=False) # Test Symbol not found with pytest.raises(SymbolNotFound): c.quote("No Dice") # Test valid case res = c.quote("fb") assert isinstance(res, Quote) validate_quote_response(res, "FB") res = c.stock("fb") assert isinstance(res, Stock) validate_quote_response(res, "FB")
def test_auth_required(): c = TDClient(authenticated=False) with pytest.raises(AuthenticationRequired): c._update_access_token()
def test_missing_credentials(): with mock.patch.dict("os.environ", clear=True): with pytest.raises(Exception) as exc_info: c = TDClient() assert c is None assert "Missing Credentials" in str(exc_info.value)
def test_stock(): c = TDClient(authenticated=False) with mock.patch.object(TDClient, "quote") as m: c.stock("fb") m.assert_called_once() m.assert_called_with("fb")