diff --git a/pandas_datareader/tests/data/yahoo_options1.html b/pandas_datareader/tests/data/yahoo_options1.html deleted file mode 100644 index 2846a2bd..00000000 --- a/pandas_datareader/tests/data/yahoo_options1.html +++ /dev/null @@ -1,6065 +0,0 @@ - - - - - AAPL Options | Yahoo! Inc. Stock - Yahoo! Finance - - - - - - - - - - - - - - - - - - - - - - - - - -
-
-
- -
-
- - -
- -
- -
- - - - - - - -
- - -
- - -
-
- - - - - -
-
-
- - - - - -
-
-
- - - - - -
- -
- - - -
-
-
-
- - - - Dow - - - - Up - - - 1.32% - - - - - - - Nasdaq - - - - Up - - - 1.60% - - - - - - -
- -
-
-
- - -
- -
-

More on AAPL

-
-
- - -

Quotes

- - -

Charts

- - -

News & Info

- - -

Company

- - -

Analyst Coverage

- - -

Ownership

- - -

Financials

- - - -
-
- -
-
- -
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
-
- - -
-
- - - - - -
-
-
- - - - -
-
-
-
-
-
-

Apple Inc. (AAPL)

- -
-
-
-
- - 104.83 - - - - - Up +1.84(1.79%) - - - NasdaqGS - As of 4:00PM EDT - -
-
| - - -
-
- -
- - -
-
-
-
-
- - - - -
-
-
- - - - - -
- -
- - - -
- - -
-
- - - - - -
-
-
- -
-
- -
-
October 24, 2014
- -
- - -
- -
- - -
-
-
- - -
-
-
-
-
- - -
-
- In The Money -
-
- - - -
-
-

Show Me Strikes From

-
- $ - to $ -
- Apply Filter - Clear Filter -
- - - - - -
- -
-
-

Show Me Strikes From

-
- $ - to $ -
- Apply Filter - Clear Filter -
- - - - - -
- - -
- - -
-
-
- - - - - -
- -
- - - -
- - -
- -
-
- - - -
-
- - - - - - - - - - - - - - - -
- - - - - - - - - - - - \ No newline at end of file diff --git a/pandas_datareader/tests/data/yahoo_options1.json b/pandas_datareader/tests/data/yahoo_options1.json new file mode 100644 index 00000000..746040a5 --- /dev/null +++ b/pandas_datareader/tests/data/yahoo_options1.json @@ -0,0 +1,2 @@ + +{"optionChain":{"result":[{"underlyingSymbol":"AAPL","expirationDates":[1473379200,1473984000,1474588800,1475193600,1475798400,1476403200,1477008000,1479427200,1481846400,1484870400,1489708800,1492732800,1497571200,1510876800,1516320000],"strikes":[75.0,80.0,85.0,90.0,91.0,92.0,93.0,94.0,94.5,95.0,95.5,96.0,96.5,97.0,97.5,98.0,98.5,99.0,99.5,100.0,101.0,102.0,103.0,104.0,105.0,106.0,107.0,108.0,109.0,110.0,111.0,112.0,113.0,114.0,115.0,116.0,117.0,118.0,119.0,120.0,121.0,123.0,125.0,140.0],"hasMiniOptions":false,"quote":{"quoteType":"EQUITY","quoteSourceName":"Delayed Quote","currency":"USD","postMarketPrice":107.86,"postMarketChange":0.16000366,"regularMarketChangePercent":-0.046415158,"regularMarketPreviousClose":107.73,"bid":107.82,"ask":107.86,"bidSize":3,"askSize":10,"messageBoardId":"finmb_24937","fullExchangeName":"NasdaqGS","averageDailyVolume3Month":32040193,"averageDailyVolume10Day":26506600,"fiftyTwoWeekLowChange":18.21,"fiftyTwoWeekLowChangePercent":0.20353189,"fiftyTwoWeekHighChange":-16.14,"fiftyTwoWeekHighChangePercent":-0.1303505,"fiftyTwoWeekLow":89.47,"fiftyTwoWeekHigh":123.82,"dividendDate":1470873600,"earningsTimestamp":1469577600,"earningsTimestampStart":1477440000,"earningsTimestampEnd":1477958400,"trailingAnnualDividendRate":2.13,"trailingPE":12.55597,"sharesOutstanding":5388440000,"bookValue":23.463,"fiftyDayAverage":105.54343,"fiftyDayAverageChange":2.1365738,"fiftyDayAverageChangePercent":0.020243552,"twoHundredDayAverage":101.387825,"twoHundredDayAverageChange":6.2921753,"twoHundredDayAverageChangePercent":0.062060464,"marketCap":580227235840,"forwardPE":12.085298,"priceToBook":4.5893536,"sourceInterval":15,"exchangeTimezoneName":"America/New_York","exchangeTimezoneShortName":"EDT","gmtOffSetMilliseconds":-14400000,"market":"us_market","exchange":"NMS","shortName":"Apple Inc.","longName":"Apple Inc.","epsTrailingTwelveMonths":8.576,"epsForward":8.91,"marketState":"POSTPOST","postMarketChangePercent":0.14856422,"postMarketTime":1473206386,"regularMarketPrice":107.68,"regularMarketTime":1473192000,"regularMarketChange":-0.05000305,"regularMarketOpen":107.82,"regularMarketDayHigh":108.3,"regularMarketDayLow":107.51,"regularMarketVolume":20744505,"symbol":"AAPL"},"options":[{"expirationDate":1473379200,"hasMiniOptions":false,"calls":[{"contractSymbol":"AAPL160909C00080000","strike":80.0,"currency":"USD","lastPrice":29.19,"change":0.0,"percentChange":0.0,"volume":2,"openInterest":0,"bid":25.55,"ask":28.4,"contractSize":"REGULAR","expiration":1473379200,"lastTradeDate":1471961437,"impliedVolatility":2.3418010205078117,"inTheMoney":true},{"contractSymbol":"AAPL160909C00090000","strike":90.0,"currency":"USD","lastPrice":17.6,"change":1.25,"percentChange":7.64526,"volume":22,"openInterest":25,"bid":17.6,"ask":17.9,"contractSize":"REGULAR","expiration":1473379200,"lastTradeDate":1472824406,"impliedVolatility":0.9765627343750001,"inTheMoney":true},{"contractSymbol":"AAPL160909C00093000","strike":93.0,"currency":"USD","lastPrice":13.98,"change":0.0,"percentChange":0.0,"volume":4,"openInterest":4,"bid":12.8,"ask":13.7,"contractSize":"REGULAR","expiration":1473379200,"lastTradeDate":1472488073,"impliedVolatility":1.0000000000000003E-5,"inTheMoney":true},{"contractSymbol":"AAPL160909C00094000","strike":94.0,"currency":"USD","lastPrice":11.66,"change":0.0,"percentChange":0.0,"volume":2,"openInterest":0,"bid":12.25,"ask":13.85,"contractSize":"REGULAR","expiration":1473379200,"lastTradeDate":1470246897,"impliedVolatility":0.9062509375,"inTheMoney":true},{"contractSymbol":"AAPL160909C00095000","strike":95.0,"currency":"USD","lastPrice":11.5,"change":0.7399998,"percentChange":6.8773212,"volume":70,"openInterest":75,"bid":11.45,"ask":11.85,"contractSize":"REGULAR","expiration":1473379200,"lastTradeDate":1472759882,"impliedVolatility":1.0000000000000003E-5,"inTheMoney":true},{"contractSymbol":"AAPL160909C00096000","strike":96.0,"currency":"USD","lastPrice":9.9,"change":0.0,"percentChange":0.0,"volume":5,"openInterest":70,"bid":9.8,"ask":10.75,"contractSize":"REGULAR","expiration":1473379200,"lastTradeDate":1472585054,"impliedVolatility":1.0000000000000003E-5,"inTheMoney":true},{"contractSymbol":"AAPL160909C00096500","strike":96.5,"currency":"USD","lastPrice":10.02,"change":0.0,"percentChange":0.0,"volume":2,"openInterest":0,"bid":10.15,"ask":10.3,"contractSize":"REGULAR","expiration":1473379200,"lastTradeDate":1472763600,"impliedVolatility":1.0000000000000003E-5,"inTheMoney":true},{"contractSymbol":"AAPL160909C00097000","strike":97.0,"currency":"USD","lastPrice":10.9,"change":0.85999966,"percentChange":8.565734,"volume":1,"openInterest":4,"bid":10.65,"ask":10.85,"contractSize":"REGULAR","expiration":1473379200,"lastTradeDate":1473184854,"impliedVolatility":0.6191444335937502,"inTheMoney":true},{"contractSymbol":"AAPL160909C00097500","strike":97.5,"currency":"USD","lastPrice":7.86,"change":0.0,"percentChange":0.0,"volume":10,"openInterest":0,"bid":10.1,"ask":10.45,"contractSize":"REGULAR","expiration":1473379200,"lastTradeDate":1470061367,"impliedVolatility":0.6269568554687501,"inTheMoney":true},{"contractSymbol":"AAPL160909C00098000","strike":98.0,"currency":"USD","lastPrice":9.43,"change":-0.85999966,"percentChange":-8.357625,"volume":11,"openInterest":14,"bid":9.55,"ask":9.9,"contractSize":"REGULAR","expiration":1473379200,"lastTradeDate":1472840251,"impliedVolatility":0.5273484765625001,"inTheMoney":true},{"contractSymbol":"AAPL160909C00098500","strike":98.5,"currency":"USD","lastPrice":8.97,"change":-0.8499994,"percentChange":-8.655799,"volume":10,"openInterest":14,"bid":9.1,"ask":9.4,"contractSize":"REGULAR","expiration":1473379200,"lastTradeDate":1472826887,"impliedVolatility":0.5429733203125001,"inTheMoney":true},{"contractSymbol":"AAPL160909C00099000","strike":99.0,"currency":"USD","lastPrice":8.61,"change":0.25999928,"percentChange":3.1137636,"volume":8,"openInterest":95,"bid":8.65,"ask":8.8,"contractSize":"REGULAR","expiration":1473379200,"lastTradeDate":1473183231,"impliedVolatility":0.5742230078125,"inTheMoney":true},{"contractSymbol":"AAPL160909C00099500","strike":99.5,"currency":"USD","lastPrice":8.45,"change":0.77,"percentChange":10.026041,"volume":11,"openInterest":94,"bid":8.15,"ask":8.3,"contractSize":"REGULAR","expiration":1473379200,"lastTradeDate":1473175386,"impliedVolatility":0.5449264257812501,"inTheMoney":true},{"contractSymbol":"AAPL160909C00100000","strike":100.0,"currency":"USD","lastPrice":7.75,"change":0.0,"percentChange":0.0,"volume":520,"openInterest":1295,"bid":7.65,"ask":7.8,"contractSize":"REGULAR","expiration":1473379200,"lastTradeDate":1473191339,"impliedVolatility":0.51758294921875,"inTheMoney":true},{"contractSymbol":"AAPL160909C00101000","strike":101.0,"currency":"USD","lastPrice":7.1,"change":0.6500001,"percentChange":10.077521,"volume":14,"openInterest":290,"bid":6.7,"ask":6.8,"contractSize":"REGULAR","expiration":1473379200,"lastTradeDate":1473170658,"impliedVolatility":0.46289599609375004,"inTheMoney":true},{"contractSymbol":"AAPL160909C00102000","strike":102.0,"currency":"USD","lastPrice":5.76,"change":-0.01999998,"percentChange":-0.34602043,"volume":39,"openInterest":538,"bid":5.7,"ask":5.85,"contractSize":"REGULAR","expiration":1473379200,"lastTradeDate":1473191215,"impliedVolatility":0.4414118359375,"inTheMoney":true},{"contractSymbol":"AAPL160909C00103000","strike":103.0,"currency":"USD","lastPrice":4.72,"change":-0.06000042,"percentChange":-1.2552389,"volume":411,"openInterest":712,"bid":4.75,"ask":4.85,"contractSize":"REGULAR","expiration":1473379200,"lastTradeDate":1473186556,"impliedVolatility":0.38086556640624997,"inTheMoney":true},{"contractSymbol":"AAPL160909C00104000","strike":104.0,"currency":"USD","lastPrice":3.85,"change":-0.03000021,"percentChange":-0.7732013,"volume":229,"openInterest":1299,"bid":3.75,"ask":3.9,"contractSize":"REGULAR","expiration":1473379200,"lastTradeDate":1473191938,"impliedVolatility":0.3437565625,"inTheMoney":true},{"contractSymbol":"AAPL160909C00105000","strike":105.0,"currency":"USD","lastPrice":2.94,"change":-0.06999993,"percentChange":-2.3255792,"volume":3007,"openInterest":4919,"bid":2.9,"ask":2.97,"contractSize":"REGULAR","expiration":1473379200,"lastTradeDate":1473191932,"impliedVolatility":0.305671005859375,"inTheMoney":true},{"contractSymbol":"AAPL160909C00106000","strike":106.0,"currency":"USD","lastPrice":2.12,"change":-0.10000014,"percentChange":-4.504511,"volume":2962,"openInterest":6232,"bid":2.09,"ask":2.14,"contractSize":"REGULAR","expiration":1473379200,"lastTradeDate":1473191989,"impliedVolatility":0.28516339843749994,"inTheMoney":true},{"contractSymbol":"AAPL160909C00107000","strike":107.0,"currency":"USD","lastPrice":1.4,"change":-0.14999998,"percentChange":-9.677419,"volume":6639,"openInterest":10599,"bid":1.41,"ask":1.43,"contractSize":"REGULAR","expiration":1473379200,"lastTradeDate":1473191996,"impliedVolatility":0.27197993652343744,"inTheMoney":true},{"contractSymbol":"AAPL160909C00108000","strike":108.0,"currency":"USD","lastPrice":0.88,"change":-0.120000005,"percentChange":-12.0,"volume":28797,"openInterest":12586,"bid":0.87,"ask":0.9,"contractSize":"REGULAR","expiration":1473379200,"lastTradeDate":1473191995,"impliedVolatility":0.2695385546875,"inTheMoney":false},{"contractSymbol":"AAPL160909C00109000","strike":109.0,"currency":"USD","lastPrice":0.53,"change":-0.060000002,"percentChange":-10.169493,"volume":8412,"openInterest":8419,"bid":0.52,"ask":0.53,"contractSize":"REGULAR","expiration":1473379200,"lastTradeDate":1473191999,"impliedVolatility":0.2710033837890625,"inTheMoney":false},{"contractSymbol":"AAPL160909C00110000","strike":110.0,"currency":"USD","lastPrice":0.31,"change":-0.030000001,"percentChange":-8.823529,"volume":27860,"openInterest":17832,"bid":0.3,"ask":0.32,"contractSize":"REGULAR","expiration":1473379200,"lastTradeDate":1473191993,"impliedVolatility":0.2836985693359374,"inTheMoney":false},{"contractSymbol":"AAPL160909C00111000","strike":111.0,"currency":"USD","lastPrice":0.19,"change":0.0,"percentChange":0.0,"volume":5989,"openInterest":5496,"bid":0.17,"ask":0.19,"contractSize":"REGULAR","expiration":1473379200,"lastTradeDate":1473191999,"impliedVolatility":0.29688203124999996,"inTheMoney":false},{"contractSymbol":"AAPL160909C00112000","strike":112.0,"currency":"USD","lastPrice":0.12,"change":0.0,"percentChange":0.0,"volume":13423,"openInterest":5721,"bid":0.11,"ask":0.12,"contractSize":"REGULAR","expiration":1473379200,"lastTradeDate":1473191985,"impliedVolatility":0.31445998046874996,"inTheMoney":false},{"contractSymbol":"AAPL160909C00113000","strike":113.0,"currency":"USD","lastPrice":0.07,"change":-0.009999998,"percentChange":-12.499998,"volume":3146,"openInterest":2663,"bid":0.06,"ask":0.08,"contractSize":"REGULAR","expiration":1473379200,"lastTradeDate":1473191660,"impliedVolatility":0.334967587890625,"inTheMoney":false},{"contractSymbol":"AAPL160909C00114000","strike":114.0,"currency":"USD","lastPrice":0.05,"change":-0.009999998,"percentChange":-16.666664,"volume":1090,"openInterest":2307,"bid":0.04,"ask":0.05,"contractSize":"REGULAR","expiration":1473379200,"lastTradeDate":1473190201,"impliedVolatility":0.34961587890624996,"inTheMoney":false},{"contractSymbol":"AAPL160909C00115000","strike":115.0,"currency":"USD","lastPrice":0.03,"change":0.0,"percentChange":0.0,"volume":1118,"openInterest":3526,"bid":0.03,"ask":0.04,"contractSize":"REGULAR","expiration":1473379200,"lastTradeDate":1473189228,"impliedVolatility":0.3789124609375,"inTheMoney":false},{"contractSymbol":"AAPL160909C00116000","strike":116.0,"currency":"USD","lastPrice":0.02,"change":-0.02,"percentChange":-50.0,"volume":484,"openInterest":972,"bid":0.01,"ask":0.03,"contractSize":"REGULAR","expiration":1473379200,"lastTradeDate":1473184057,"impliedVolatility":0.398443515625,"inTheMoney":false},{"contractSymbol":"AAPL160909C00117000","strike":117.0,"currency":"USD","lastPrice":0.02,"change":-0.01,"percentChange":-33.333336,"volume":296,"openInterest":1090,"bid":0.01,"ask":0.02,"contractSize":"REGULAR","expiration":1473379200,"lastTradeDate":1473177141,"impliedVolatility":0.414068359375,"inTheMoney":false},{"contractSymbol":"AAPL160909C00118000","strike":118.0,"currency":"USD","lastPrice":0.01,"change":-0.02,"percentChange":-66.66667,"volume":21,"openInterest":735,"bid":0.01,"ask":0.02,"contractSize":"REGULAR","expiration":1473379200,"lastTradeDate":1473189143,"impliedVolatility":0.45313046875,"inTheMoney":false},{"contractSymbol":"AAPL160909C00119000","strike":119.0,"currency":"USD","lastPrice":0.01,"change":-0.02,"percentChange":-66.66667,"volume":408,"openInterest":951,"bid":0.01,"ask":0.01,"contractSize":"REGULAR","expiration":1473379200,"lastTradeDate":1473187006,"impliedVolatility":0.445318046875,"inTheMoney":false},{"contractSymbol":"AAPL160909C00120000","strike":120.0,"currency":"USD","lastPrice":0.03,"change":-0.04,"percentChange":-57.142853,"volume":946,"openInterest":1107,"bid":0.02,"ask":0.03,"contractSize":"REGULAR","expiration":1473379200,"lastTradeDate":1472845688,"impliedVolatility":0.5390671093750001,"inTheMoney":false},{"contractSymbol":"AAPL160909C00121000","strike":121.0,"currency":"USD","lastPrice":0.02,"change":-0.01,"percentChange":-33.333336,"volume":1490,"openInterest":240,"bid":0.02,"ask":0.03,"contractSize":"REGULAR","expiration":1473379200,"lastTradeDate":1472840012,"impliedVolatility":0.570316796875,"inTheMoney":false},{"contractSymbol":"AAPL160909C00123000","strike":123.0,"currency":"USD","lastPrice":0.02,"change":-0.01,"percentChange":-33.333336,"volume":576,"openInterest":1,"bid":0.02,"ask":0.03,"contractSize":"REGULAR","expiration":1473379200,"lastTradeDate":1472845909,"impliedVolatility":0.64062859375,"inTheMoney":false},{"contractSymbol":"AAPL160909C00125000","strike":125.0,"currency":"USD","lastPrice":0.01,"change":0.0,"percentChange":0.0,"volume":105,"openInterest":119,"bid":0.0,"ask":0.18,"contractSize":"REGULAR","expiration":1473379200,"lastTradeDate":1472572425,"impliedVolatility":0.84961087890625,"inTheMoney":false},{"contractSymbol":"AAPL160909C00140000","strike":140.0,"currency":"USD","lastPrice":0.02,"change":0.0,"percentChange":0.0,"volume":2,"openInterest":2,"bid":0.0,"ask":0.03,"contractSize":"REGULAR","expiration":1473379200,"lastTradeDate":1471060094,"impliedVolatility":1.09375453125,"inTheMoney":false}],"puts":[{"contractSymbol":"AAPL160909P00075000","strike":75.0,"currency":"USD","lastPrice":0.02,"change":0.0,"percentChange":0.0,"volume":1,"openInterest":1,"bid":0.0,"ask":0.04,"contractSize":"REGULAR","expiration":1473379200,"lastTradeDate":1470439323,"impliedVolatility":1.5468772656249998,"inTheMoney":false},{"contractSymbol":"AAPL160909P00080000","strike":80.0,"currency":"USD","lastPrice":0.01,"change":0.0,"percentChange":0.0,"volume":1,"openInterest":0,"bid":0.01,"ask":0.02,"contractSize":"REGULAR","expiration":1473379200,"lastTradeDate":1473215185,"impliedVolatility":1.2500037499999999,"inTheMoney":false},{"contractSymbol":"AAPL160909P00085000","strike":85.0,"currency":"USD","lastPrice":0.02,"change":-0.02,"percentChange":-50.0,"volume":2,"openInterest":0,"bid":0.0,"ask":0.02,"contractSize":"REGULAR","expiration":1473379200,"lastTradeDate":1472233093,"impliedVolatility":0.9687503125,"inTheMoney":false},{"contractSymbol":"AAPL160909P00090000","strike":90.0,"currency":"USD","lastPrice":0.01,"change":-0.01,"percentChange":-50.0,"volume":212,"openInterest":1990,"bid":0.01,"ask":0.03,"contractSize":"REGULAR","expiration":1473379200,"lastTradeDate":1472824927,"impliedVolatility":0.8281267187499999,"inTheMoney":false},{"contractSymbol":"AAPL160909P00091000","strike":91.0,"currency":"USD","lastPrice":0.01,"change":-0.01,"percentChange":-50.0,"volume":100,"openInterest":16,"bid":0.01,"ask":0.01,"contractSize":"REGULAR","expiration":1473379200,"lastTradeDate":1472828283,"impliedVolatility":0.7187528125,"inTheMoney":false},{"contractSymbol":"AAPL160909P00092000","strike":92.0,"currency":"USD","lastPrice":0.01,"change":-0.01,"percentChange":-50.0,"volume":13,"openInterest":25,"bid":0.01,"ask":0.02,"contractSize":"REGULAR","expiration":1473379200,"lastTradeDate":1472831555,"impliedVolatility":0.710940390625,"inTheMoney":false},{"contractSymbol":"AAPL160909P00093000","strike":93.0,"currency":"USD","lastPrice":0.01,"change":-0.04,"percentChange":-79.99999,"volume":100,"openInterest":7,"bid":0.01,"ask":0.02,"contractSize":"REGULAR","expiration":1473379200,"lastTradeDate":1472831711,"impliedVolatility":0.6640658593750002,"inTheMoney":false},{"contractSymbol":"AAPL160909P00094000","strike":94.0,"currency":"USD","lastPrice":0.01,"change":-0.03,"percentChange":-75.0,"volume":130,"openInterest":178,"bid":0.01,"ask":0.02,"contractSize":"REGULAR","expiration":1473379200,"lastTradeDate":1472841500,"impliedVolatility":0.6250037500000001,"inTheMoney":false},{"contractSymbol":"AAPL160909P00094500","strike":94.5,"currency":"USD","lastPrice":0.02,"change":-0.030000001,"percentChange":-60.000004,"volume":490,"openInterest":125,"bid":0.01,"ask":0.02,"contractSize":"REGULAR","expiration":1473379200,"lastTradeDate":1472844019,"impliedVolatility":0.6015664843750002,"inTheMoney":false},{"contractSymbol":"AAPL160909P00095000","strike":95.0,"currency":"USD","lastPrice":0.01,"change":-0.04,"percentChange":-79.99999,"volume":20,"openInterest":753,"bid":0.01,"ask":0.01,"contractSize":"REGULAR","expiration":1473379200,"lastTradeDate":1473168600,"impliedVolatility":0.5468795312500001,"inTheMoney":false},{"contractSymbol":"AAPL160909P00095500","strike":95.5,"currency":"USD","lastPrice":0.01,"change":-0.01,"percentChange":-50.0,"volume":662,"openInterest":2428,"bid":0.01,"ask":0.01,"contractSize":"REGULAR","expiration":1473379200,"lastTradeDate":1473170496,"impliedVolatility":0.5312546875,"inTheMoney":false},{"contractSymbol":"AAPL160909P00096000","strike":96.0,"currency":"USD","lastPrice":0.01,"change":-0.01,"percentChange":-50.0,"volume":487,"openInterest":441,"bid":0.01,"ask":0.01,"contractSize":"REGULAR","expiration":1473379200,"lastTradeDate":1473185064,"impliedVolatility":0.51562984375,"inTheMoney":false},{"contractSymbol":"AAPL160909P00096500","strike":96.5,"currency":"USD","lastPrice":0.01,"change":-0.03,"percentChange":-75.0,"volume":139,"openInterest":206,"bid":0.01,"ask":0.01,"contractSize":"REGULAR","expiration":1473379200,"lastTradeDate":1473191404,"impliedVolatility":0.48438015625,"inTheMoney":false},{"contractSymbol":"AAPL160909P00097000","strike":97.0,"currency":"USD","lastPrice":0.01,"change":-0.02,"percentChange":-66.66667,"volume":15,"openInterest":830,"bid":0.01,"ask":0.02,"contractSize":"REGULAR","expiration":1473379200,"lastTradeDate":1473191307,"impliedVolatility":0.5117236328125,"inTheMoney":false},{"contractSymbol":"AAPL160909P00097500","strike":97.5,"currency":"USD","lastPrice":0.01,"change":-0.02,"percentChange":-66.66667,"volume":27,"openInterest":2256,"bid":0.01,"ask":0.02,"contractSize":"REGULAR","expiration":1473379200,"lastTradeDate":1473191161,"impliedVolatility":0.49219257812500006,"inTheMoney":false},{"contractSymbol":"AAPL160909P00098000","strike":98.0,"currency":"USD","lastPrice":0.02,"change":-0.01,"percentChange":-33.333336,"volume":580,"openInterest":343,"bid":0.01,"ask":0.02,"contractSize":"REGULAR","expiration":1473379200,"lastTradeDate":1473190428,"impliedVolatility":0.4687553125,"inTheMoney":false},{"contractSymbol":"AAPL160909P00098500","strike":98.5,"currency":"USD","lastPrice":0.02,"change":-0.030000001,"percentChange":-60.000004,"volume":505,"openInterest":181,"bid":0.01,"ask":0.02,"contractSize":"REGULAR","expiration":1473379200,"lastTradeDate":1473191473,"impliedVolatility":0.445318046875,"inTheMoney":false},{"contractSymbol":"AAPL160909P00099000","strike":99.0,"currency":"USD","lastPrice":0.02,"change":-0.02,"percentChange":-50.0,"volume":1069,"openInterest":432,"bid":0.01,"ask":0.02,"contractSize":"REGULAR","expiration":1473379200,"lastTradeDate":1473184090,"impliedVolatility":0.42188078125,"inTheMoney":false},{"contractSymbol":"AAPL160909P00099500","strike":99.5,"currency":"USD","lastPrice":0.03,"change":-0.01,"percentChange":-25.0,"volume":200,"openInterest":686,"bid":0.02,"ask":0.03,"contractSize":"REGULAR","expiration":1473379200,"lastTradeDate":1473181417,"impliedVolatility":0.42578699218750005,"inTheMoney":false},{"contractSymbol":"AAPL160909P00100000","strike":100.0,"currency":"USD","lastPrice":0.03,"change":-0.020000001,"percentChange":-40.000004,"volume":987,"openInterest":1821,"bid":0.02,"ask":0.03,"contractSize":"REGULAR","expiration":1473379200,"lastTradeDate":1473190423,"impliedVolatility":0.4023497265625,"inTheMoney":false},{"contractSymbol":"AAPL160909P00101000","strike":101.0,"currency":"USD","lastPrice":0.05,"change":0.0,"percentChange":0.0,"volume":754,"openInterest":2214,"bid":0.03,"ask":0.04,"contractSize":"REGULAR","expiration":1473379200,"lastTradeDate":1473191958,"impliedVolatility":0.37500625,"inTheMoney":false},{"contractSymbol":"AAPL160909P00102000","strike":102.0,"currency":"USD","lastPrice":0.06,"change":-0.010000002,"percentChange":-14.285716,"volume":973,"openInterest":3829,"bid":0.05,"ask":0.07,"contractSize":"REGULAR","expiration":1473379200,"lastTradeDate":1473191313,"impliedVolatility":0.36133451171875,"inTheMoney":false},{"contractSymbol":"AAPL160909P00103000","strike":103.0,"currency":"USD","lastPrice":0.1,"change":-0.009999998,"percentChange":-9.090907,"volume":4345,"openInterest":4192,"bid":0.09,"ask":0.1,"contractSize":"REGULAR","expiration":1473379200,"lastTradeDate":1473191904,"impliedVolatility":0.33399103515625,"inTheMoney":false},{"contractSymbol":"AAPL160909P00104000","strike":104.0,"currency":"USD","lastPrice":0.14,"change":-0.030000001,"percentChange":-17.647058,"volume":2663,"openInterest":4303,"bid":0.14,"ask":0.15,"contractSize":"REGULAR","expiration":1473379200,"lastTradeDate":1473191687,"impliedVolatility":0.30762411132812495,"inTheMoney":false},{"contractSymbol":"AAPL160909P00105000","strike":105.0,"currency":"USD","lastPrice":0.25,"change":-0.030000001,"percentChange":-10.714286,"volume":5470,"openInterest":6385,"bid":0.24,"ask":0.25,"contractSize":"REGULAR","expiration":1473379200,"lastTradeDate":1473191992,"impliedVolatility":0.2890696093749999,"inTheMoney":false},{"contractSymbol":"AAPL160909P00106000","strike":106.0,"currency":"USD","lastPrice":0.43,"change":-0.00999999,"percentChange":-2.272725,"volume":5814,"openInterest":8340,"bid":0.42,"ask":0.43,"contractSize":"REGULAR","expiration":1473379200,"lastTradeDate":1473191995,"impliedVolatility":0.2758861474609374,"inTheMoney":false},{"contractSymbol":"AAPL160909P00107000","strike":107.0,"currency":"USD","lastPrice":0.75,"change":-0.04000002,"percentChange":-5.063294,"volume":12512,"openInterest":6312,"bid":0.72,"ask":0.74,"contractSize":"REGULAR","expiration":1473379200,"lastTradeDate":1473191995,"impliedVolatility":0.2690502783203125,"inTheMoney":false},{"contractSymbol":"AAPL160909P00108000","strike":108.0,"currency":"USD","lastPrice":1.2,"change":-0.029999971,"percentChange":-2.439022,"volume":10303,"openInterest":5459,"bid":1.17,"ask":1.2,"contractSize":"REGULAR","expiration":1473379200,"lastTradeDate":1473191992,"impliedVolatility":0.264655791015625,"inTheMoney":true},{"contractSymbol":"AAPL160909P00109000","strike":109.0,"currency":"USD","lastPrice":1.83,"change":-0.00999999,"percentChange":-0.5434777,"volume":3998,"openInterest":2099,"bid":1.79,"ask":1.84,"contractSize":"REGULAR","expiration":1473379200,"lastTradeDate":1473191938,"impliedVolatility":0.26807372558593745,"inTheMoney":true},{"contractSymbol":"AAPL160909P00110000","strike":110.0,"currency":"USD","lastPrice":2.63,"change":0.05000019,"percentChange":1.937992,"volume":1427,"openInterest":3755,"bid":2.57,"ask":2.61,"contractSize":"REGULAR","expiration":1473379200,"lastTradeDate":1473191664,"impliedVolatility":0.27295648925781246,"inTheMoney":true},{"contractSymbol":"AAPL160909P00111000","strike":111.0,"currency":"USD","lastPrice":3.5,"change":0.049999952,"percentChange":1.449274,"volume":55,"openInterest":406,"bid":3.4,"ask":3.5,"contractSize":"REGULAR","expiration":1473379200,"lastTradeDate":1473189055,"impliedVolatility":0.2919992675781249,"inTheMoney":true},{"contractSymbol":"AAPL160909P00112000","strike":112.0,"currency":"USD","lastPrice":4.28,"change":-0.21999979,"percentChange":-4.8888845,"volume":55,"openInterest":458,"bid":4.35,"ask":4.45,"contractSize":"REGULAR","expiration":1473379200,"lastTradeDate":1473176894,"impliedVolatility":0.32031929687499994,"inTheMoney":true},{"contractSymbol":"AAPL160909P00113000","strike":113.0,"currency":"USD","lastPrice":5.42,"change":-0.27999973,"percentChange":-4.9122763,"volume":59,"openInterest":94,"bid":5.3,"ask":5.4,"contractSize":"REGULAR","expiration":1473379200,"lastTradeDate":1473183727,"impliedVolatility":0.334967587890625,"inTheMoney":true},{"contractSymbol":"AAPL160909P00114000","strike":114.0,"currency":"USD","lastPrice":6.15,"change":-0.55999994,"percentChange":-8.345752,"volume":292,"openInterest":79,"bid":6.25,"ask":6.4,"contractSize":"REGULAR","expiration":1473379200,"lastTradeDate":1473174223,"impliedVolatility":0.38281867187499996,"inTheMoney":true},{"contractSymbol":"AAPL160909P00115000","strike":115.0,"currency":"USD","lastPrice":7.4,"change":-0.5,"percentChange":-6.329114,"volume":75,"openInterest":159,"bid":7.25,"ask":7.4,"contractSize":"REGULAR","expiration":1473379200,"lastTradeDate":1473189675,"impliedVolatility":0.42774009765625004,"inTheMoney":true},{"contractSymbol":"AAPL160909P00116000","strike":116.0,"currency":"USD","lastPrice":6.86,"change":0.0,"percentChange":0.0,"volume":2,"openInterest":2,"bid":7.5,"ask":7.7,"contractSize":"REGULAR","expiration":1473379200,"lastTradeDate":1471554007,"impliedVolatility":1.0000000000000003E-5,"inTheMoney":true},{"contractSymbol":"AAPL160909P00118000","strike":118.0,"currency":"USD","lastPrice":10.75,"change":0.0,"percentChange":0.0,"volume":20,"openInterest":20,"bid":11.3,"ask":12.35,"contractSize":"REGULAR","expiration":1473379200,"lastTradeDate":1472678938,"impliedVolatility":1.2470740771484374,"inTheMoney":true},{"contractSymbol":"AAPL160909P00120000","strike":120.0,"currency":"USD","lastPrice":12.48,"change":0.5699997,"percentChange":4.7858915,"volume":1,"openInterest":11,"bid":12.15,"ask":12.45,"contractSize":"REGULAR","expiration":1473379200,"lastTradeDate":1472827495,"impliedVolatility":0.70117486328125,"inTheMoney":true}]}]}],"error":null}} \ No newline at end of file diff --git a/pandas_datareader/tests/data/yahoo_options2.html b/pandas_datareader/tests/data/yahoo_options2.html deleted file mode 100644 index bae9c193..00000000 --- a/pandas_datareader/tests/data/yahoo_options2.html +++ /dev/null @@ -1,5853 +0,0 @@ - - - - - AAPL Option Chain | Yahoo! Inc. Stock - Yahoo! Finance - - - - - - - - - - - - - - - - - - - - - - - - - -
-
-
- -
-
- - -
- -
- -
- - - - - - - -
- - -
- - -
-
- - - - - -
-
-
- - - - - -
-
-
- - - - - -
- -
- - - -
-
-
-
- - - - Dow - - - - Up - - - 0.58% - - - - - - - Nasdaq - - - - Down - - - 0.06% - - - - - - -
- -
-
-
- - -
- -
-

More on AAPL

-
-
- - -

Quotes

- - -

Charts

- - -

News & Info

- - -

Company

- - -

Analyst Coverage

- - -

Ownership

- - -

Financials

- - - -
-
- -
-
- -
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
-
- - -
-
- - - - - -
-
-
- - - - -
-
-
-
-
-
-

Apple Inc. (AAPL)

- -
-
-
-
- - 108.86 - - - - - Up +0.26(0.24%) - - - NasdaqGS - As of 4:00PM EST - -
-
| - - After Hours: - 108.86 0.00 (0.00%) 7:59PM EST - - -
-
- -
- - -
-
-
-
-
- - - - -
-
-
- - - - - -
- -
- - - -
- - -
-
- - - - - -
-
-
- -
-
- -
-
November 7, 2014
- -
- - - -
-
-
- - -
-
-
-
-
- - -
-
- In The Money -
-
- - - -
-
-

Show Me Strikes From

-
- $ - to $ -
- Apply Filter - Clear Filter -
- - - - - -
- -
-
-

Show Me Strikes From

-
- $ - to $ -
- Apply Filter - Clear Filter -
- - - - - -
- - -
- - -
-
-
- - - - - -
- -
- - - -
- - -
- -
-
- - - -
-
- - - - - - - - - - - - - - - -
- - - - - - - - - - - - \ No newline at end of file diff --git a/pandas_datareader/tests/data/yahoo_options2.json b/pandas_datareader/tests/data/yahoo_options2.json new file mode 100644 index 00000000..a685ae11 --- /dev/null +++ b/pandas_datareader/tests/data/yahoo_options2.json @@ -0,0 +1 @@ +{"optionChain":{"result":[],"error":null}} \ No newline at end of file diff --git a/pandas_datareader/tests/data/yahoo_options3.html b/pandas_datareader/tests/data/yahoo_options3.html deleted file mode 100644 index 6e79bb9b..00000000 --- a/pandas_datareader/tests/data/yahoo_options3.html +++ /dev/null @@ -1,2807 +0,0 @@ - - - - - SPWR Option Chain | Yahoo! Inc. Stock - Yahoo! Finance - - - - - - - - - - - - - - - - - - - - - - - - - -
-
-
- -
  • FirefoxInstall the new Firefox »
  • -
    - - -
    - -
    - -
    - - - - - - - -
    - - -
    - - -
    - -
    - - - -
    -
    -
    -
    - - - - Dow - - - - Down - - - 0.58% - - - - - - - Nasdaq - - - - Down - - - 0.32% - - - - - - -
    - -
    -
    -
    - - -
    - -
    -

    More on SPWR

    -
    -
    - - -

    Quotes

    - - -

    Charts

    - - -

    News & Info

    - - -

    Company

    - - -

    Analyst Coverage

    - - -

    Ownership

    - - -

    Financials

    - - -
    -
    - -
    -
    - -
    -
    -
    -
    -
    - -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    - - -
    - - -
    -
    -
    -
    -
    -
    -

    SunPower Corporation (SPWR)

    - -
    -
    -
    -
    - - 33.05 - - - - - Up +0.07(0.21%) - - - NASDAQ - As of 4:00PM EDT - -
    -
    | - - After Hours: - 33.10 Up +0.05 (0.15%) 7:47PM EDT - - -
    -
    - -
    - - -
    -
    -
    -
    -
    - - -
    - - - -
    - - -
    -
    - -
    -
    May 1, 2015
    - -
    - - - -
    -
    -
    - - -
    -
    -
    -
    -
    - - -
    -
    - In The Money -
    -
    - - - -
    -
    -

    Show Me Strikes From

    -
    - $ - to $ -
    - Apply Filter - Clear Filter -
    - - - - - -
    - -
    -
    -

    Show Me Strikes From

    -
    - $ - to $ -
    - Apply Filter - Clear Filter -
    - - - - - -
    - - -
    -
    - - - -
    - - -
    - -
    -
    - - - -
    -
    - - - - - - - - - - - - - - - -
    - - - - - - - - - - - - \ No newline at end of file diff --git a/pandas_datareader/tests/test_yahoo_options.py b/pandas_datareader/tests/test_yahoo_options.py index 77f751a4..a2ce988a 100644 --- a/pandas_datareader/tests/test_yahoo_options.py +++ b/pandas_datareader/tests/test_yahoo_options.py @@ -7,7 +7,6 @@ import nose import pandas.util.testing as tm -from pandas_datareader.tests._utils import _skip_if_no_lxml import pandas_datareader.data as web from pandas_datareader._utils import RemoteDataError @@ -18,7 +17,6 @@ class TestYahooOptions(tm.TestCase): @classmethod def setUpClass(cls): super(TestYahooOptions, cls).setUpClass() - _skip_if_no_lxml() # aapl has monthlies cls.aapl = web.Options('aapl', 'yahoo') @@ -30,10 +28,9 @@ def setUpClass(cls): cls.year = cls.year + 1 cls.expiry = datetime(cls.year, cls.month, 1) cls.dirpath = tm.get_data_path() - cls.html1 = 'file://' + os.path.join(cls.dirpath, 'yahoo_options1.html') - cls.html2 = 'file://' + os.path.join(cls.dirpath, 'yahoo_options2.html') - cls.html3 = 'file://' + os.path.join(cls.dirpath, 'yahoo_options3.html') # Empty table GH#22 - cls.data1 = cls.aapl._option_frames_from_url(cls.html1)['puts'] + cls.json1 = 'file://' + os.path.join(cls.dirpath, 'yahoo_options1.json') + cls.json2 = 'file://' + os.path.join(cls.dirpath, 'yahoo_options2.json') # Empty table GH#22 + cls.data1 = cls.aapl._process_data(cls.aapl._parse_url(cls.json1)) @classmethod def tearDownClass(cls): @@ -49,12 +46,13 @@ def assert_option_result(self, df): exp_columns = pd.Index(['Last', 'Bid', 'Ask', 'Chg', 'PctChg', 'Vol', 'Open_Int', 'IV', 'Root', 'IsNonstandard', 'Underlying', - 'Underlying_Price', 'Quote_Time']) + 'Underlying_Price', 'Quote_Time', 'Last_Trade_Date', 'JSON']) tm.assert_index_equal(df.columns, exp_columns) tm.assert_equal(df.index.names, [u'Strike', u'Expiry', u'Type', u'Symbol']) dtypes = [np.dtype(x) for x in ['float64'] * 5 + - ['int64', 'int64', 'float64', 'object', 'bool', 'object', 'float64', 'datetime64[ns]']] + ['int64', 'int64', 'float64', 'object', 'bool', 'object', 'float64', 'datetime64[ns]', + 'datetime64[ns]', 'object']] tm.assert_series_equal(df.dtypes, pd.Series(dtypes, index=exp_columns)) def test_get_options_data(self): @@ -103,7 +101,7 @@ def test_get_put_data(self): def test_get_expiry_dates(self): try: - dates, _ = self.aapl._get_expiry_dates_and_links() + dates = self.aapl._get_expiry_dates() except RemoteDataError as e: # pragma: no cover raise nose.SkipTest(e) self.assertTrue(len(dates) > 1) @@ -139,21 +137,13 @@ def test_get_underlying_price(self): # GH7 try: options_object = web.Options('^spxpm', 'yahoo') - url = options_object._yahoo_url_from_expiry(options_object.expiry_dates[0]) - root = options_object._parse_url(url) - quote_price = options_object._underlying_price_from_root(root) + quote_price = options_object.underlying_price except RemoteDataError as e: # pragma: no cover raise nose.SkipTest(e) self.assertTrue(isinstance(quote_price, float)) # Tests the weekend quote time format - price, quote_time = self.aapl._underlying_price_and_time_from_url(self.html1) - self.assertTrue(isinstance(price, (int, float, complex))) - self.assertTrue(isinstance(quote_time, (datetime, pd.Timestamp))) - - # Tests the EDT page format - # regression test for #8741 - price, quote_time = self.aapl._underlying_price_and_time_from_url(self.html2) + price, quote_time = self.aapl.underlying_price, self.aapl.quote_time self.assertTrue(isinstance(price, (int, float, complex))) self.assertTrue(isinstance(quote_time, (datetime, pd.Timestamp))) @@ -194,7 +184,7 @@ def test_month_year(self): def test_empty_table(self): # GH22 - empty = self.aapl._option_frames_from_url(self.html3)['puts'] + empty = self.aapl._process_data(self.aapl._parse_url(self.json2)) self.assertTrue(len(empty) == 0) if __name__ == '__main__': diff --git a/pandas_datareader/yahoo/options.py b/pandas_datareader/yahoo/options.py index 73429ad8..0149ac86 100644 --- a/pandas_datareader/yahoo/options.py +++ b/pandas_datareader/yahoo/options.py @@ -1,11 +1,12 @@ import warnings import datetime as dt import numpy as np +import json from pandas import to_datetime -from pandas import concat, DatetimeIndex, Series +from pandas import concat, DatetimeIndex, Series, MultiIndex +from pandas.io.json import read_json from pandas.tseries.offsets import MonthEnd -from pandas.io.parsers import TextParser from pandas import DataFrame from pandas_datareader._utils import RemoteDataError @@ -17,23 +18,8 @@ CUR_DAY = dt.datetime.now().day -def _two_char(s): - return '{0:0>2}'.format(s) - - -def _unpack(row, kind='td'): - return [val.text_content().strip() for val in row.findall(kind)] - - -def _parse_options_data(table): - header = table.findall('thead/tr') - header = _unpack(header[0], kind='th') - rows = table.findall('tbody/tr') - data = [_unpack(r) for r in rows] - if len(data) > 0: - return TextParser(data, names=header, thousands=',').get_chunk() - else: # Empty table - return DataFrame(columns=header) +def _parse_options_data(jd): + return read_json(jd) class Options(_OptionBaseReader): @@ -78,8 +64,7 @@ class Options(_OptionBaseReader): >>> all_data = aapl.get_all_data() """ - _OPTIONS_BASE_URL = 'http://finance.yahoo.com/q/op?s={sym}' - _FINANCE_BASE_URL = 'http://finance.yahoo.com' + _OPTIONS_BASE_URL = 'https://query1.finance.yahoo.com/v7/finance/options/{sym}' def get_options_data(self, month=None, year=None, expiry=None): """ @@ -112,6 +97,7 @@ def get_options_data(self, month=None, year=None, expiry=None): Columns: Last: Last option price, float Chg: Change from prior day, float + PctChg: Change from prior day in percent, float Bid: Bid price, float Ask: Ask price, float Vol: Volume traded, int64 @@ -120,6 +106,10 @@ def get_options_data(self, month=None, year=None, expiry=None): Underlying: Ticker of the underlying security, string Underlying_Price: Price of the underlying security, float64 Quote_Time: Time of the quote, Timestamp + Last_Trade_Date: Time of the last trade for this expiry and strike, Timestamp + IV: Implied volatility, float + JSON: Parsed json object, json + Useful to extract other returned key/value pairs as needed Notes ----- @@ -144,42 +134,19 @@ def get_options_data(self, month=None, year=None, expiry=None): for f in (self.get_put_data, self.get_call_data)]).sortlevel() - def _get_option_frames_from_yahoo(self, expiry): - url = self._yahoo_url_from_expiry(expiry) - option_frames = self._option_frames_from_url(url) - frame_name = '_frames' + self._expiry_to_string(expiry) - setattr(self, frame_name, option_frames) - return option_frames - - @staticmethod - def _expiry_to_string(expiry): - m1 = _two_char(expiry.month) - d1 = _two_char(expiry.day) - return str(expiry.year)[-2:] + m1 + d1 + def _option_from_url(self, url): - def _yahoo_url_from_expiry(self, expiry): + jd = self._parse_url(url) + result = jd['optionChain']['result'] try: - expiry_links = self._expiry_links - - except AttributeError: # pragma: no cover - _, expiry_links = self._get_expiry_dates_and_links() - - return self._FINANCE_BASE_URL + expiry_links[expiry] - - def _option_frames_from_url(self, url): - - root = self._parse_url(url) - try: - calls = root.xpath('//*[@id="optionsCallsTable"]/div[2]/div/table')[0] - puts = root.xpath('//*[@id="optionsPutsTable"]/div[2]/div/table')[0] + calls = result['options']['calls'] + puts = result['options']['puts'] except IndexError: - raise RemoteDataError('Option Table not available for url: %s' % url) + raise RemoteDataError('Option json not available for url: %s' % url) - if not hasattr(self, 'underlying_price'): - try: - self.underlying_price, self.quote_time = self._underlying_price_and_time_from_url(url) - except IndexError: - self.underlying_price, self.quote_time = np.nan, np.nan + self.underlying_price = result['quote']['regularMarketPrice'] if result['quote']['marketState'] == 'PRE' else result['quote']['preMarketPrice'] + quote_unix_time = result['quote']['regularMarketTime'] if result['quote']['marketState'] == 'PRE' else result['quote']['preMarketTime'] + self.quote_time = dt.datetime.fromtimestamp(quote_unix_time) calls = _parse_options_data(calls) puts = _parse_options_data(puts) @@ -189,39 +156,6 @@ def _option_frames_from_url(self, url): return {'calls': calls, 'puts': puts} - def _underlying_price_and_time_from_url(self, url): - root = self._parse_url(url) - underlying_price = self._underlying_price_from_root(root) - quote_time = self._quote_time_from_root(root) - return underlying_price, quote_time - - @staticmethod - def _underlying_price_from_root(root): - underlying_price = root.xpath('.//*[@class="time_rtq_ticker Fz-30 Fw-b"]')[0]\ - .getchildren()[0].text - underlying_price = underlying_price.replace(',', '') # GH11 - - try: - underlying_price = float(underlying_price) - except ValueError: - underlying_price = np.nan - - return underlying_price - - @staticmethod - def _quote_time_from_root(root): - # Gets the time of the quote, note this is actually the time of the underlying price. - try: - quote_time_text = root.xpath('.//*[@class="time_rtq Fz-m"]')[0].getchildren()[1].getchildren()[0].text - # TODO: Enable timezone matching when strptime can match EST with %Z - quote_time_text = quote_time_text.split(' ')[0] - quote_time = dt.datetime.strptime(quote_time_text, "%I:%M%p") - quote_time = quote_time.replace(year=CUR_YEAR, month=CUR_MONTH, day=CUR_DAY) - except ValueError: - quote_time = np.nan - - return quote_time - def _get_option_data(self, expiry, name): frame_name = '_frames' + self._expiry_to_string(expiry) @@ -268,6 +202,7 @@ def get_call_data(self, month=None, year=None, expiry=None): Columns: Last: Last option price, float Chg: Change from prior day, float + PctChg: Change from prior day in percent, float Bid: Bid price, float Ask: Ask price, float Vol: Volume traded, int64 @@ -276,6 +211,10 @@ def get_call_data(self, month=None, year=None, expiry=None): Underlying: Ticker of the underlying security, string Underlying_Price: Price of the underlying security, float64 Quote_Time: Time of the quote, Timestamp + Last_Trade_Date: Time of the last trade for this expiry and strike, Timestamp + IV: Implied volatility, float + JSON: Parsed json object, json + Useful to extract other returned key/value pairs as needed Notes ----- @@ -329,6 +268,7 @@ def get_put_data(self, month=None, year=None, expiry=None): Columns: Last: Last option price, float Chg: Change from prior day, float + PctChg: Change from prior day in percent, float Bid: Bid price, float Ask: Ask price, float Vol: Volume traded, int64 @@ -337,6 +277,10 @@ def get_put_data(self, month=None, year=None, expiry=None): Underlying: Ticker of the underlying security, string Underlying_Price: Price of the underlying security, float64 Quote_Time: Time of the quote, Timestamp + Last_Trade_Date: Time of the last trade for this expiry and strike, Timestamp + IV: Implied volatility, float + JSON: Parsed json object, json + Useful to extract other returned key/value pairs as needed Notes ----- @@ -396,12 +340,35 @@ def get_near_stock_price(self, above_below=2, call=True, put=False, desired. If there isn't data as far out as the user has asked for then + Index: + Strike: Option strike, int + Expiry: Option expiry, Timestamp + Type: Call or Put, string + Symbol: Option symbol as reported on Yahoo, string + Columns: + Last: Last option price, float + Chg: Change from prior day, float + PctChg: Change from prior day in percent, float + Bid: Bid price, float + Ask: Ask price, float + Vol: Volume traded, int64 + Open_Int: Open interest, int64 + IsNonstandard: True if the the deliverable is not 100 shares, otherwise false + Underlying: Ticker of the underlying security, string + Underlying_Price: Price of the underlying security, float64 + Quote_Time: Time of the quote, Timestamp + Last_Trade_Date: Time of the last trade for this expiry and strike, Timestamp + IV: Implied volatility, float + JSON: Parsed json object, json + Useful to extract other returned key/value pairs as needed + Note: Format of returned data frame is dependent on Yahoo and may change. """ expiry = self._try_parse_dates(year, month, expiry) data = self._get_data_in_date_range(expiry, call=call, put=put) - return self._chop_data(data, above_below, self.underlying_price) + underlying_price = data.Underlying_Price[0] + return self._chop_data(data, above_below, underlying_price) def _chop_data(self, df, above_below=2, underlying_price=None): """Returns a data frame only options that are near the current stock price.""" @@ -530,6 +497,7 @@ def get_forward_data(self, months, call=True, put=False, near=False, Columns: Last: Last option price, float Chg: Change from prior day, float + PctChg: Change from prior day in percent, float Bid: Bid price, float Ask: Ask price, float Vol: Volume traded, int64 @@ -538,13 +506,17 @@ def get_forward_data(self, months, call=True, put=False, near=False, Underlying: Ticker of the underlying security, string Underlying_Price: Price of the underlying security, float64 Quote_Time: Time of the quote, Timestamp + Last_Trade_Date: Time of the last trade for this expiry and strike, Timestamp + IV: Implied volatility, float + JSON: Parsed json object, json + Useful to extract other returned key/value pairs as needed Note: Format of returned data frame is dependent on Yahoo and may change. """ warnings.warn("get_forward_data() is deprecated", FutureWarning) end_date = dt.date.today() + MonthEnd(months) - dates = (date for date in self.expiry_dates if date <= end_date.date()) + dates = [date for date in self.expiry_dates if date <= end_date.date()] data = self._get_data_in_date_range(dates, call=call, put=put) if near: data = self._chop_data(data, above_below=above_below) @@ -577,6 +549,7 @@ def get_all_data(self, call=True, put=True): Columns: Last: Last option price, float Chg: Change from prior day, float + PctChg: Change from prior day in percent, float Bid: Bid price, float Ask: Ask price, float Vol: Volume traded, int64 @@ -585,30 +558,51 @@ def get_all_data(self, call=True, put=True): Underlying: Ticker of the underlying security, string Underlying_Price: Price of the underlying security, float64 Quote_Time: Time of the quote, Timestamp + Last_Trade_Date: Time of the last trade for this expiry and strike, Timestamp + IV: Implied volatility, float + JSON: Parsed json object, json + Useful to extract other returned key/value pairs as needed Note: Format of returned data frame is dependent on Yahoo and may change. """ - - expiry_dates = self.expiry_dates - return self._get_data_in_date_range(dates=expiry_dates, call=call, put=put) + return self._load_data() def _get_data_in_date_range(self, dates, call=True, put=True): to_ret = Series({'calls': call, 'puts': put}) to_ret = to_ret[to_ret].index - data = [] - for name in to_ret: - for expiry_date in dates: - nam = name + self._expiry_to_string(expiry_date) - try: # Try to access on the instance - frame = getattr(self, nam) - except AttributeError: - frame = self._get_option_data(expiry=expiry_date, name=name) - data.append(frame) + df = self._load_data(dates) + types = [typ for typ in to_ret] - return concat(data).sortlevel() + df_filtered_by_type = df[df.index.map(lambda x: x[2] in types)] + df_filtered_by_expiry = df_filtered_by_type[df_filtered_by_type.index.get_level_values('Expiry').isin(dates)] + return df_filtered_by_expiry + + @property + def underlying_price(self): + """ + Returns the underlying price. + """ + try: + underlying_price = self._underlying_price + except AttributeError: + data = self.get_options_data() + underlying_price = data.Underlying_Price[0] + return underlying_price + + @property + def quote_time(self): + """ + Returns the quote time. + """ + try: + quote_time = self._quote_time + except AttributeError: + data = self.get_options_data() + quote_time = data.Quote_Time[0] + return quote_time @property def expiry_dates(self): @@ -618,81 +612,152 @@ def expiry_dates(self): try: expiry_dates = self._expiry_dates except AttributeError: - expiry_dates, _ = self._get_expiry_dates_and_links() + expiry_dates = self._get_expiry_dates() return expiry_dates - def _get_expiry_dates_and_links(self): + def _get_expiry_dates(self): """ Gets available expiry dates. Returns ------- - Tuple of: List of datetime.date objects - Dict of datetime.date objects as keys and corresponding links """ url = self._OPTIONS_BASE_URL.format(sym=self.symbol) - root = self._parse_url(url) + jd = self._parse_url(url) - try: - links = root.xpath('//*[@id="options_menu"]/form/select/option') - except IndexError: # pragma: no cover - raise RemoteDataError('Expiry dates not available') - - expiry_dates = [dt.datetime.strptime(element.text, "%B %d, %Y").date() for element in links] - links = [element.attrib['data-selectbox-link'] for element in links] + expiry_dates =\ + [dt.datetime.utcfromtimestamp(ts).date() for ts in jd['optionChain']['result'][0]['expirationDates']] if len(expiry_dates) == 0: raise RemoteDataError('Data not available') # pragma: no cover - expiry_links = dict(zip(expiry_dates, links)) - self._expiry_links = expiry_links self._expiry_dates = expiry_dates - return expiry_dates, expiry_links + return expiry_dates def _parse_url(self, url): """ - Downloads and parses a URL, returns xml root. + Downloads and parses a URL into a json object. + Parameters + ---------- + url : String + The url to load and parse + + Returns + ------- + A JSON object """ - try: - from lxml.html import parse - except ImportError: # pragma: no cover - raise ImportError("Please install lxml if you want to use the " - "{0!r} class".format(self.__class__.__name__)) - doc = parse(self._read_url_as_StringIO(url)) - root = doc.getroot() - if root is None: # pragma: no cover - raise RemoteDataError("Parsed URL {0!r} has no root" - "element".format(url)) - return root - - def _process_data(self, frame, type): + jd = json.loads(self._read_url_as_StringIO(url).read()) + if jd is None: # pragma: no cover + raise RemoteDataError("Parsed URL {0!r} is not a valid json object".format(url)) + return jd + + def _process_data(self, jd): """ - Adds columns for Expiry, IsNonstandard (ie: deliverable is not 100 shares) - and Tag (the tag indicating what is actually deliverable, None if standard). + Parse JSON data into the DataFrame + + Also adds computed columns for: + IsNonstandard (ie: deliverable is not 100 shares) + Parameters + ---------- + jd : json object + a json object containing the data to process + + Returns + ------- + pandas.DataFrame + A DataFrame with requested options data. """ - frame.columns = ['Strike', 'Symbol', 'Last', 'Bid', 'Ask', 'Chg', 'PctChg', 'Vol', 'Open_Int', 'IV'] - frame["Rootexp"] = frame.Symbol.str[0:-9] - frame["Root"] = frame.Rootexp.str[0:-6] - frame["Expiry"] = to_datetime(frame.Rootexp.str[-6:], format='%y%m%d') - # Removes dashes in equity ticker to map to option ticker. - # Ex: BRK-B to BRKB140517C00100000 - frame["IsNonstandard"] = frame['Root'] != self.symbol.replace('-', '') - del frame["Rootexp"] - frame["Underlying"] = self.symbol - try: - frame['Underlying_Price'] = self.underlying_price - frame["Quote_Time"] = self.quote_time - except AttributeError: # pragma: no cover - frame['Underlying_Price'] = np.nan - frame["Quote_Time"] = np.nan - frame.rename(columns={'Open Int': 'Open_Int'}, inplace=True) - frame['IV'] = frame['IV'].str.replace(',', '').str.strip('%').astype(float) / 100 - frame['PctChg'] = frame['PctChg'].str.replace(',', '').str.strip('%').astype(float) / 100 - frame['Type'] = type - frame.set_index(['Strike', 'Expiry', 'Type', 'Symbol'], inplace=True) - - return frame + + columns = ['Last', 'Bid', 'Ask', 'Chg', 'PctChg', 'Vol', + 'Open_Int', 'IV', 'Root', 'IsNonstandard', 'Underlying', 'Underlying_Price', 'Quote_Time', + 'Last_Trade_Date', 'JSON'] + indexes = ['Strike', 'Expiry', 'Type', 'Symbol'] + rows_list, index = self._process_rows(jd) + if len(rows_list) > 0: + df = DataFrame(rows_list, columns=columns, index=MultiIndex.from_tuples(index, names=indexes)) + else: + df = DataFrame(columns=columns) + + df['IsNonstandard'] = df['Root'] != self.symbol.replace('-', '') + + return df.sort_index() + + def _process_rows(self, jd): + rows_list = [] + index = [] + + # handle no results + if len(jd['optionChain']['result']) <= 0: + return rows_list, index + + quote = jd['optionChain']['result'][0]['quote'] + for option in jd['optionChain']['result'][0]['options']: + for typ in ['calls', 'puts']: + options_by_type = option[typ] + for option_by_strike in options_by_type: + d = {} + for dkey, rkey, ntype in [('Last', 'lastPrice', float), ('Bid', 'bid', float), + ('Ask', 'ask', float), ('Chg', 'change', float), + ('PctChg', 'percentChange', float), ('Vol', 'volume', int), + ('Open_Int', 'openInterest', int), ('IV', 'impliedVolatility', float), + ('Last_Trade_Date', 'lastTradeDate', int)]: + try: + d[dkey] = ntype(option_by_strike[rkey]) + except (KeyError, ValueError): + pass + d['JSON'] = option_by_strike + d['Root'] = option_by_strike['contractSymbol'][:-15] + d['Underlying'] = self.symbol + + d['Underlying_Price'] = quote['regularMarketPrice'] + quote_unix_time = quote['regularMarketTime'] + if quote['marketState'] == 'PRE' and 'preMarketPrice' in quote: + d['Underlying_Price'] = quote['preMarketPrice'] + quote_unix_time = quote['preMarketTime'] + elif quote['marketState'] == 'POSTPOST' and 'postMarketPrice' in quote: + d['Underlying_Price'] = quote['postMarketPrice'] + quote_unix_time = quote['postMarketTime'] + d['Quote_Time'] = dt.datetime.utcfromtimestamp(quote_unix_time) + + self._underlying_price = d['Underlying_Price'] + self._quote_time = d['Quote_Time'] + + d['Last_Trade_Date'] = dt.datetime.utcfromtimestamp(d['Last_Trade_Date']) + + rows_list.append(d) + index.append((float(option_by_strike['strike']), + dt.datetime.utcfromtimestamp(option_by_strike['expiration']), + typ, + option_by_strike['contractSymbol'])) + return rows_list, index + + def _load_data(self, exp_dates=None): + """ + Loads options data. + + Parameters + ---------- + exp_dates : tuple of datetimes, optional(default=None) + The expiry dates to load options data for. If none is specified, uses all expiry dates available for the + symbol. + + Returns + ------- + pandas.DataFrame + A DataFrame with requested options data. + """ + epoch = dt.datetime.utcfromtimestamp(0) + if exp_dates is None: + exp_dates = self._get_expiry_dates() + exp_unix_times = [int((dt.datetime(exp_date.year, exp_date.month, exp_date.day) - epoch).total_seconds()) + for exp_date in exp_dates] + data = [] + for exp_date in exp_unix_times: + url = (self._OPTIONS_BASE_URL + '?date={exp_date}').format(sym=self.symbol, exp_date=exp_date) + jd = self._parse_url(url) + data.append(self._process_data(jd)) + return concat(data).sortlevel()