github.com/polygon-io/client-go@v1.16.4/rest/reference_test.go (about)

     1  package polygon_test
     2  
     3  import (
     4  	"context"
     5  	"encoding/json"
     6  	"testing"
     7  	"time"
     8  
     9  	"github.com/jarcoal/httpmock"
    10  	polygon "github.com/polygon-io/client-go/rest"
    11  	"github.com/polygon-io/client-go/rest/models"
    12  	"github.com/stretchr/testify/assert"
    13  )
    14  
    15  func TestListTickers(t *testing.T) {
    16  	c := polygon.New("API_KEY")
    17  
    18  	httpmock.ActivateNonDefault(c.HTTP.GetClient())
    19  	defer httpmock.DeactivateAndReset()
    20  
    21  	ticker1 := `{
    22  	"ticker": "A",
    23  	"name": "Agilent Technologies Inc.",
    24  	"market": "stocks",
    25  	"locale": "us",
    26  	"primary_exchange": "XNYS",
    27  	"type": "CS",
    28  	"active": true,
    29  	"currency_name": "usd",
    30  	"cik": "0001090872",
    31  	"composite_figi": "BBG000BWQYZ5",
    32  	"share_class_figi": "BBG001SCTQY4",
    33  	"last_updated_utc": "2021-04-25T00:00:00.000Z"
    34  }`
    35  
    36  	expectedResponse := `{
    37  	"status": "OK",
    38  	"count": 1,
    39  	"next_url": "https://api.polygon.io/v3/reference/tickers?cursor=YWN0aXZlPXRydWUmZGF0ZT0yMDIxLTA0LTI1JmxpbWl0PTEmb3JkZXI9YXNjJnBhZ2VfbWFya2VyPUElN0M5YWRjMjY0ZTgyM2E1ZjBiOGUyNDc5YmZiOGE1YmYwNDVkYzU0YjgwMDcyMWE2YmI1ZjBjMjQwMjU4MjFmNGZiJnNvcnQ9dGlja2Vy",
    40  	"request_id": "e70013d92930de90e089dc8fa098888e",
    41  	"results": [
    42  ` + indent(true, ticker1, "\t\t") + `
    43  	]
    44  }`
    45  
    46  	registerResponder("https://api.polygon.io/v3/reference/tickers?active=true&cik=5&cusip=10&date=2021-07-22&exchange=XNAS&limit=2&market=stocks&order=asc&sort=ticker&type=CS", expectedResponse)
    47  	registerResponder("https://api.polygon.io/v3/reference/tickers?cursor=YWN0aXZlPXRydWUmZGF0ZT0yMDIxLTA0LTI1JmxpbWl0PTEmb3JkZXI9YXNjJnBhZ2VfbWFya2VyPUElN0M5YWRjMjY0ZTgyM2E1ZjBiOGUyNDc5YmZiOGE1YmYwNDVkYzU0YjgwMDcyMWE2YmI1ZjBjMjQwMjU4MjFmNGZiJnNvcnQ9dGlja2Vy", "{}")
    48  	iter := c.ListTickers(context.Background(), models.ListTickersParams{}.
    49  		WithType("CS").WithMarket(models.AssetStocks).
    50  		WithExchange("XNAS").WithCUSIP(10).WithCIK(5).
    51  		WithDate(models.Date(time.Date(2021, 7, 22, 0, 0, 0, 0, time.UTC))).WithActive(true).
    52  		WithSort(models.TickerSymbol).WithOrder(models.Asc).WithLimit(2))
    53  
    54  	// iter creation
    55  	assert.Nil(t, iter.Err())
    56  	assert.NotNil(t, iter.Item())
    57  
    58  	// first item
    59  	assert.True(t, iter.Next())
    60  	assert.Nil(t, iter.Err())
    61  	var expect models.Ticker
    62  	err := json.Unmarshal([]byte(ticker1), &expect)
    63  	assert.Nil(t, err)
    64  	assert.Equal(t, expect, iter.Item())
    65  
    66  	// end of list
    67  	assert.False(t, iter.Next())
    68  	assert.Nil(t, iter.Err())
    69  }
    70  
    71  func TestGetTickerDetails(t *testing.T) {
    72  	c := polygon.New("API_KEY")
    73  
    74  	httpmock.ActivateNonDefault(c.HTTP.GetClient())
    75  	defer httpmock.DeactivateAndReset()
    76  
    77  	expectedResponse := `{
    78  	"status": "OK",
    79  	"request_id": "31d59dda-80e5-4721-8496-d0d32a654afe",
    80  	"results": {
    81  		"ticker": "AAPL",
    82  		"name": "Apple Inc.",
    83  		"market": "stocks",
    84  		"locale": "us",
    85  		"primary_exchange": "XNAS",
    86  		"type": "CS",
    87  		"active": true,
    88  		"currency_name": "usd",
    89  		"cik": "0000320193",
    90  		"composite_figi": "BBG000B9XRY4",
    91  		"share_class_figi": "BBG001S5N8V8",
    92  		"last_updated_utc": "2021-04-25T00:00:00.000Z",
    93  		"market_cap": 2771126040150,
    94  		"phone_number": "(408) 996-1010",
    95  		"address": {
    96  			"address1": "One Apple Park Way",
    97  			"city": "Cupertino",
    98  			"state": "CA"
    99  		},
   100  		"description": "Apple designs a wide variety of consumer electronic devices, including smartphones (iPhone), tablets (iPad), PCs (Mac), smartwatches (Apple Watch), AirPods, and TV boxes (Apple TV), among others. The iPhone makes up the majority of Apple's total revenue. In addition, Apple offers its customers a variety of services such as Apple Music, iCloud, Apple Care, Apple TV+, Apple Arcade, Apple Card, and Apple Pay, among others. Apple's products run internally developed software and semiconductors, and the firm is well known for its integration of hardware, software and services. Apple's products are distributed online as well as through company-owned stores and third-party retailers. The company generates roughly 40% of its revenue from the Americas, with the remainder earned internationally.",
   101  		"sic_code": "3571",
   102  		"sic_description": "ELECTRONIC COMPUTERS",
   103  		"homepage_url": "https://www.apple.com",
   104  		"total_employees": 154000,
   105  		"list_date": "1980-12-12",
   106  		"branding": {
   107  			"logo_url": "https://api.polygon.io/v1/reference/company-branding/d3d3LmFwcGxlLmNvbQ/images/2022-01-10_logo.svg",
   108  			"icon_url": "https://api.polygon.io/v1/reference/company-branding/d3d3LmFwcGxlLmNvbQ/images/2022-01-10_icon.png"
   109  		},
   110  		"share_class_shares_outstanding": 16406400000,
   111  		"weighted_shares_outstanding": 16334371000
   112  	}
   113  }`
   114  
   115  	registerResponder("https://api.polygon.io/v3/reference/tickers/A?date=2021-07-22", expectedResponse)
   116  	res, err := c.GetTickerDetails(context.Background(), models.GetTickerDetailsParams{
   117  		Ticker: "A",
   118  	}.WithDate(models.Date(time.Date(2021, 7, 22, 0, 0, 0, 0, time.UTC))))
   119  	assert.Nil(t, err)
   120  
   121  	var expect models.GetTickerDetailsResponse
   122  	err = json.Unmarshal([]byte(expectedResponse), &expect)
   123  	assert.Nil(t, err)
   124  	assert.Equal(t, &expect, res)
   125  }
   126  
   127  func TestListTickerNews(t *testing.T) {
   128  	c := polygon.New("API_KEY")
   129  
   130  	httpmock.ActivateNonDefault(c.HTTP.GetClient())
   131  	defer httpmock.DeactivateAndReset()
   132  
   133  	news1 := `{
   134  	"id": "nJsSJJdwViHZcw5367rZi7_qkXLfMzacXBfpv-vD9UA",
   135  	"publisher": {
   136  		"name": "Benzinga",
   137  		"homepage_url": "https://www.benzinga.com/",
   138  		"logo_url": "https://s3.polygon.io/public/public/assets/news/logos/benzinga.svg",
   139  		"favicon_url": "https://s3.polygon.io/public/public/assets/news/favicons/benzinga.ico"
   140  	},
   141  	"title": "Cathie Wood Adds More Coinbase, Skillz, Trims Square",
   142  	"author": "Rachit Vats",
   143  	"published_utc": "2021-04-26T02:33:17.000Z",
   144  	"article_url": "https://www.benzinga.com/markets/cryptocurrency/21/04/20784086/cathie-wood-adds-more-coinbase-skillz-trims-square",
   145  	"tickers": [
   146  		"DOCU",
   147  		"DDD",
   148  		"NIU",
   149  		"ARKF",
   150  		"NVDA",
   151  		"SKLZ",
   152  		"PCAR",
   153  		"MASS",
   154  		"PSTI",
   155  		"SPFR",
   156  		"TREE",
   157  		"PHR",
   158  		"IRDM",
   159  		"BEAM",
   160  		"ARKW",
   161  		"ARKK",
   162  		"ARKG",
   163  		"PSTG",
   164  		"SQ",
   165  		"IONS",
   166  		"SYRS"
   167  	],
   168  	"amp_url": "https://amp.benzinga.com/amp/content/20784086",
   169  	"image_url": "https://cdn2.benzinga.com/files/imagecache/og_image_social_share_1200x630/images/story/2012/andre-francois-mckenzie-auhr4gcqcce-unsplash.jpg?width=720",
   170  	"description": "Cathie Wood-led Ark Investment Management on Friday snapped up another 221,167 shares...",
   171  	"keywords": [
   172  		"Sector ETFs",
   173  		"Penny Stocks",
   174  		"Cryptocurrency",
   175  		"Small Cap",
   176  		"Markets",
   177  		"Trading Ideas",
   178  		"ETFs"
   179  	]
   180  }`
   181  
   182  	expectedResponse := `{
   183  	"status": "OK",
   184  	"count": 1,
   185  	"next_url": "https://api.polygon.io/v2/reference/news?cursor=eyJsaW1pdCI6MSwic29ydCI6InB1Ymxpc2hlZF91dGMiLCJvcmRlciI6ImFzY2VuZGluZyIsInRpY2tlciI6e30sInB1Ymxpc2hlZF91dGMiOnsiZ3RlIjoiMjAyMS0wNC0yNiJ9LCJzZWFyY2hfYWZ0ZXIiOlsxNjE5NDA0Mzk3MDAwLG51bGxdfQ",
   186  	"request_id": "831afdb0b8078549fed053476984947a",
   187  	"results": [
   188  ` + indent(true, news1, "\t\t") + `
   189  	]
   190  }`
   191  
   192  	registerResponder("https://api.polygon.io/v2/reference/news?limit=2&order=asc&published_utc.lt=1626912000000&sort=published_utc&ticker.lte=AAPL", expectedResponse)
   193  	registerResponder("https://api.polygon.io/v2/reference/news?cursor=eyJsaW1pdCI6MSwic29ydCI6InB1Ymxpc2hlZF91dGMiLCJvcmRlciI6ImFzY2VuZGluZyIsInRpY2tlciI6e30sInB1Ymxpc2hlZF91dGMiOnsiZ3RlIjoiMjAyMS0wNC0yNiJ9LCJzZWFyY2hfYWZ0ZXIiOlsxNjE5NDA0Mzk3MDAwLG51bGxdfQ", "{}")
   194  	iter := c.ListTickerNews(context.Background(), models.ListTickerNewsParams{}.
   195  		WithTicker(models.LTE, "AAPL").WithPublishedUTC(models.LT, models.Millis(time.Date(2021, 7, 22, 0, 0, 0, 0, time.UTC))).
   196  		WithSort(models.PublishedUTC).WithOrder(models.Asc).WithLimit(2))
   197  
   198  	// iter creation
   199  	assert.Nil(t, iter.Err())
   200  	assert.NotNil(t, iter.Item())
   201  
   202  	// first item
   203  	assert.True(t, iter.Next())
   204  	assert.Nil(t, iter.Err())
   205  	var expect models.TickerNews
   206  	err := json.Unmarshal([]byte(news1), &expect)
   207  	assert.Nil(t, err)
   208  	assert.Equal(t, expect, iter.Item())
   209  
   210  	// end of list
   211  	assert.False(t, iter.Next())
   212  	assert.Nil(t, iter.Err())
   213  }
   214  
   215  func TestGetTickerTypes(t *testing.T) {
   216  	c := polygon.New("API_KEY")
   217  
   218  	httpmock.ActivateNonDefault(c.HTTP.GetClient())
   219  	defer httpmock.DeactivateAndReset()
   220  
   221  	expectedResponse := `{
   222  	"status": "OK",
   223  	"request_id": "31d59dda-80e5-4721-8496-d0d32a654afe",
   224  	"count": 1,
   225  	"results": [
   226  		{
   227  			"asset_class": "stocks",
   228  			"code": "CS",
   229  			"description": "Common Stock",
   230  			"locale": "us"
   231  		}
   232  	]
   233  }`
   234  
   235  	registerResponder("https://api.polygon.io/v3/reference/tickers/types?asset_class=stocks&locale=us", expectedResponse)
   236  	res, err := c.GetTickerTypes(context.Background(), models.GetTickerTypesParams{}.WithAssetClass("stocks").WithLocale(models.US))
   237  	assert.Nil(t, err)
   238  
   239  	var expect models.GetTickerTypesResponse
   240  	err = json.Unmarshal([]byte(expectedResponse), &expect)
   241  	assert.Nil(t, err)
   242  	assert.Equal(t, &expect, res)
   243  }
   244  
   245  func TestGetMarketHolidays(t *testing.T) {
   246  	c := polygon.New("API_KEY")
   247  
   248  	httpmock.ActivateNonDefault(c.HTTP.GetClient())
   249  	defer httpmock.DeactivateAndReset()
   250  
   251  	expectedResponse := `[
   252  	{
   253  		"exchange": "NYSE",
   254  		"name": "Thanksgiving",
   255  		"date": "2020-11-26",
   256  		"status": "closed"
   257  	},
   258  	{
   259  		"exchange": "NASDAQ",
   260  		"name": "Thanksgiving",
   261  		"date": "2020-11-26",
   262  		"status": "closed"
   263  	},
   264  	{
   265  		"exchange": "OTC",
   266  		"name": "Thanksgiving",
   267  		"date": "2020-11-26",
   268  		"status": "closed"
   269  	},
   270  	{
   271  		"exchange": "NASDAQ",
   272  		"name": "Thanksgiving",
   273  		"date": "2020-11-27",
   274  		"status": "early-close",
   275  		"open": "2020-11-27T14:30:00.000Z",
   276  		"close": "2020-11-27T18:00:00.000Z"
   277  	},
   278  	{
   279  		"exchange": "NYSE",
   280  		"name": "Thanksgiving",
   281  		"date": "2020-11-27",
   282  		"status": "early-close",
   283  		"open": "2020-11-27T14:30:00.000Z",
   284  		"close": "2020-11-27T18:00:00.000Z"
   285  	}
   286  ]`
   287  
   288  	registerResponder("https://api.polygon.io/v1/marketstatus/upcoming", expectedResponse)
   289  	res, err := c.GetMarketHolidays(context.Background())
   290  	assert.Nil(t, err)
   291  
   292  	var expect models.GetMarketHolidaysResponse
   293  	err = json.Unmarshal([]byte(expectedResponse), &expect)
   294  	assert.Nil(t, err)
   295  	assert.Equal(t, &expect, res)
   296  }
   297  
   298  func TestGetMarketStatus(t *testing.T) {
   299  	c := polygon.New("API_KEY")
   300  
   301  	httpmock.ActivateNonDefault(c.HTTP.GetClient())
   302  	defer httpmock.DeactivateAndReset()
   303  
   304  	expectedResponse := `{
   305  	"afterHours": true,
   306  	"currencies": {
   307  		"crypto": "open",
   308  		"fx": "open"
   309  	},
   310  	"earlyHours": false,
   311  	"exchanges": {
   312  		"nasdaq": "extended-hours",
   313  		"nyse": "extended-hours",
   314  		"otc": "closed"
   315  	},
   316  	"market": "extended-hours",
   317  	"serverTime": "2022-05-17T10:26:06-04:00"
   318  }`
   319  
   320  	registerResponder("https://api.polygon.io/v1/marketstatus/now", expectedResponse)
   321  	res, err := c.GetMarketStatus(context.Background())
   322  	assert.Nil(t, err)
   323  
   324  	var expect models.GetMarketStatusResponse
   325  	err = json.Unmarshal([]byte(expectedResponse), &expect)
   326  	assert.Nil(t, err)
   327  	assert.Equal(t, &expect, res)
   328  }
   329  
   330  func TestListSplits(t *testing.T) {
   331  	c := polygon.New("API_KEY")
   332  
   333  	httpmock.ActivateNonDefault(c.HTTP.GetClient())
   334  	defer httpmock.DeactivateAndReset()
   335  
   336  	split := `{
   337  	"execution_date": "2020-08-31",
   338  	"split_from": 1.0,
   339  	"split_to": 4,
   340  	"ticker": "AAPL"
   341  }`
   342  
   343  	expectedResponse := `{
   344  	"status": "OK",
   345  	"request_id": "2b539ae65c1478dee109b7397bd591b2",
   346  	"results": [
   347  ` + indent(true, split, "\t\t") + `
   348  	]
   349  }`
   350  
   351  	registerResponder("https://api.polygon.io/v3/reference/splits?execution_date=2021-07-22&limit=2&order=asc&reverse_split=false&sort=ticker&ticker=AAPL", expectedResponse)
   352  	iter := c.ListSplits(context.Background(), models.ListSplitsParams{}.
   353  		WithTicker(models.EQ, "AAPL").WithExecutionDate(models.EQ, models.Date(time.Date(2021, 7, 22, 0, 0, 0, 0, time.UTC))).WithReverseSplit(false).
   354  		WithSort(models.TickerSymbol).WithOrder(models.Asc).WithLimit(2))
   355  
   356  	// iter creation
   357  	assert.Nil(t, iter.Err())
   358  	assert.NotNil(t, iter.Item())
   359  
   360  	// first item
   361  	assert.True(t, iter.Next())
   362  	assert.Nil(t, iter.Err())
   363  	var expect models.Split
   364  	err := json.Unmarshal([]byte(split), &expect)
   365  	assert.Nil(t, err)
   366  	assert.Equal(t, expect, iter.Item())
   367  
   368  	// end of list
   369  	assert.False(t, iter.Next())
   370  	assert.Nil(t, iter.Err())
   371  }
   372  
   373  func TestListDividends(t *testing.T) {
   374  	c := polygon.New("API_KEY")
   375  
   376  	httpmock.ActivateNonDefault(c.HTTP.GetClient())
   377  	defer httpmock.DeactivateAndReset()
   378  
   379  	dividend := `{
   380  	"cash_amount": 0.59375,
   381  	"declaration_date": "2020-09-09",
   382  	"dividend_type": "CD",
   383  	"ex_dividend_date": "2025-06-12",
   384  	"frequency": 4,
   385  	"pay_date": "2025-06-30",
   386  	"record_date": "2025-06-15",
   387  	"ticker": "CSSEN"
   388  }`
   389  
   390  	expectedResponse := `{
   391  	"status": "OK",
   392  	"request_id": "eca6d9a0d8dc1cd1b29d2d3112fe938e",
   393  	"next_url": "https://api.polygon.io/v3/reference/dividends?cursor=YXA9MjUmYXM9JmxpbWl0PTEwJm9yZGVyPWRlc2Mmc29ydD1leF9kaXZpZGVuZF9kYXRlJnRpY2tlcj1DU1NFTg",
   394  	"results": [
   395  ` + indent(true, dividend, "\t\t") + `
   396  	]
   397  }`
   398  
   399  	registerResponder("https://api.polygon.io/v3/reference/dividends?dividend_type=CD&ticker=CSSEN", expectedResponse)
   400  	registerResponder("https://api.polygon.io/v3/reference/dividends?cursor=YXA9MjUmYXM9JmxpbWl0PTEwJm9yZGVyPWRlc2Mmc29ydD1leF9kaXZpZGVuZF9kYXRlJnRpY2tlcj1DU1NFTg", "{}")
   401  	iter := c.ListDividends(context.Background(), models.ListDividendsParams{}.WithTicker(models.EQ, "CSSEN").WithDividendType(models.DividendCD))
   402  
   403  	// iter creation
   404  	assert.Nil(t, iter.Err())
   405  	assert.NotNil(t, iter.Item())
   406  
   407  	// first item
   408  	assert.True(t, iter.Next())
   409  	assert.Nil(t, iter.Err())
   410  	var expect models.Dividend
   411  	err := json.Unmarshal([]byte(dividend), &expect)
   412  	assert.Nil(t, err)
   413  	assert.Equal(t, expect, iter.Item())
   414  
   415  	// end of list
   416  	assert.False(t, iter.Next())
   417  	assert.Nil(t, iter.Err())
   418  }
   419  
   420  func TestListConditions(t *testing.T) {
   421  	c := polygon.New("API_KEY")
   422  
   423  	httpmock.ActivateNonDefault(c.HTTP.GetClient())
   424  	defer httpmock.DeactivateAndReset()
   425  
   426  	condition := `{
   427  	"asset_class": "stocks",
   428  	"data_types": [
   429  		"trade"
   430  	],
   431  	"id": 1,
   432  	"legacy": false,
   433  	"name": "Acquisition",
   434  	"sip_mapping": {
   435  		"UTP": "A"
   436  	},
   437  	"type": "sale_condition",
   438  	"update_rules": {
   439  		"consolidated": {
   440  			"updates_high_low": true,
   441  			"updates_open_close": true,
   442  			"updates_volume": true
   443  		},
   444  		"market_center": {
   445  			"updates_high_low": true,
   446  			"updates_open_close": true,
   447  			"updates_volume": true
   448  		}
   449  	}
   450  }`
   451  
   452  	expectedResponse := `{
   453  	"status": "OK",
   454  	"request_id": "4599a4e2ba5e19e2e732f711e97b0d84",
   455  	"count": 1,
   456  	"next_url": "https://api.polygon.io/v3/reference/conditions?cursor=YXA9MiZhcz0mYXNzZXRfY2xhc3M9c3RvY2tzJmRhdGFfdHlwZT10cmFkZSZsaW1pdD0yJnNvcnQ9YXNzZXRfY2xhc3M",
   457  	"results": [
   458  ` + indent(true, condition, "\t\t") + `
   459  	]
   460  }`
   461  
   462  	registerResponder("https://api.polygon.io/v3/reference/conditions?asset_class=stocks&data_type=trade&limit=1", expectedResponse)
   463  	registerResponder("https://api.polygon.io/v3/reference/conditions?cursor=YXA9MiZhcz0mYXNzZXRfY2xhc3M9c3RvY2tzJmRhdGFfdHlwZT10cmFkZSZsaW1pdD0yJnNvcnQ9YXNzZXRfY2xhc3M", "{}")
   464  	iter := c.ListConditions(context.Background(), models.ListConditionsParams{}.WithAssetClass(models.AssetStocks).WithDataType(models.DataTrade).WithLimit(1))
   465  
   466  	// iter creation
   467  	assert.Nil(t, iter.Err())
   468  	assert.NotNil(t, iter.Item())
   469  
   470  	// first item
   471  	assert.True(t, iter.Next())
   472  	assert.Nil(t, iter.Err())
   473  	var expect models.Condition
   474  	err := json.Unmarshal([]byte(condition), &expect)
   475  	assert.Nil(t, err)
   476  	assert.Equal(t, expect, iter.Item())
   477  
   478  	// end of list
   479  	assert.False(t, iter.Next())
   480  	assert.Nil(t, iter.Err())
   481  }
   482  
   483  func TestGetExchanges(t *testing.T) {
   484  	c := polygon.New("API_KEY")
   485  
   486  	httpmock.ActivateNonDefault(c.HTTP.GetClient())
   487  	defer httpmock.DeactivateAndReset()
   488  
   489  	expectedResponse := `{
   490  	"status": "OK",
   491  	"request_id": "c784b78622b5a68c932af78a68b5907c",
   492  	"count": 1,
   493  	"results": [
   494  		{
   495  			"acronym": "AMEX",
   496  			"asset_class": "stocks",
   497  			"id": 1,
   498  			"locale": "us",
   499  			"mic": "XASE",
   500  			"name": "NYSE American, LLC",
   501  			"operating_mic": "XNYS",
   502  			"participant_id": "A",
   503  			"type": "exchange",
   504  			"url": "https://www.nyse.com/markets/nyse-american"
   505  		}
   506  	]
   507  }`
   508  
   509  	registerResponder("https://api.polygon.io/v3/reference/exchanges?asset_class=stocks&locale=us", expectedResponse)
   510  	res, err := c.GetExchanges(context.Background(), models.GetExchangesParams{}.WithAssetClass(models.AssetStocks).WithLocale(models.US))
   511  	assert.Nil(t, err)
   512  
   513  	var expect models.GetExchangesResponse
   514  	err = json.Unmarshal([]byte(expectedResponse), &expect)
   515  	assert.Nil(t, err)
   516  	assert.Equal(t, &expect, res)
   517  }
   518  
   519  func TestGetOptionsContract(t *testing.T) {
   520  	c := polygon.New("API_KEY")
   521  
   522  	httpmock.ActivateNonDefault(c.HTTP.GetClient())
   523  	defer httpmock.DeactivateAndReset()
   524  
   525  	expectedResponse := `{
   526  	"results": {
   527  		"cfi": "OCASPS",
   528  		"contract_type": "call",
   529  		"exercise_style": "american",
   530  		"expiration_date": "2024-01-19",
   531  		"primary_exchange": "BATO",
   532  		"shares_per_contract": 100,
   533  		"strike_price": 2.5,
   534  		"ticker": "O:EVRI240119C00002500",
   535  		"underlying_ticker": "EVRI"
   536  	},
   537  	"status": "OK",
   538  	"request_id": "52fccf652441fc4d4fd35e2d0d2dd1f2"
   539  }`
   540  
   541  	registerResponder("https://api.polygon.io/v3/reference/options/contracts/O:EVRI240119C00002500", expectedResponse)
   542  	res, err := c.GetOptionsContract(context.Background(), models.GetOptionsContractParams{
   543  		Ticker: "O:EVRI240119C00002500",
   544  	}.WithAsOf(models.Date(time.Date(2022, 5, 16, 0, 0, 0, 0, time.Local))))
   545  	assert.Nil(t, err)
   546  
   547  	var expect models.GetOptionsContractResponse
   548  	err = json.Unmarshal([]byte(expectedResponse), &expect)
   549  	assert.Nil(t, err)
   550  	assert.Equal(t, &expect, res)
   551  }
   552  
   553  func TestListOptionsContracts(t *testing.T) {
   554  	c := polygon.New("API_KEY")
   555  
   556  	httpmock.ActivateNonDefault(c.HTTP.GetClient())
   557  	defer httpmock.DeactivateAndReset()
   558  
   559  	contract1 := `{
   560  	"cfi": "OCASPS",
   561  	"contract_type": "call",
   562  	"exercise_style": "american",
   563  	"expiration_date": "2022-05-20",
   564  	"primary_exchange": "BATO",
   565  	"shares_per_contract": 100,
   566  	"strike_price": 65,
   567  	"ticker": "O:A220520C00065000",
   568  	"underlying_ticker": "A"
   569  }`
   570  
   571  	contract2 := `{
   572  	"cfi": "OCASPS",
   573  	"contract_type": "call",
   574  	"exercise_style": "american",
   575  	"expiration_date": "2022-05-20",
   576  	"primary_exchange": "BATO",
   577  	"shares_per_contract": 100,
   578  	"strike_price": 70,
   579  	"ticker": "O:A220520C00070000",
   580  	"underlying_ticker": "A"
   581  }`
   582  
   583  	expectedResponse := `{
   584  	"status": "OK",
   585  	"request_id": "975d5e1aacc6c147c94934b016b8d1a7",
   586  	"next_url": "https://api.polygon.io/v3/reference/options/contracts?cursor=YXA9JTdCJTIySUQlMjIlM0ElMjIyNzI2MTY3OTUxMjgzOTI1NTI5JTIyJTJDJTIyU3RhcnREYXRlVXRjJTIyJTNBJTdCJTIyVGltZSUyMiUzQSUyMjIwMjEtMDktMjFUMDAlM0EwMCUzQTAwWiUyMiUyQyUyMlZhbGlkJTIyJTNBdHJ1ZSU3RCUyQyUyMkVuZERhdGVVdGMlMjIlM0ElN0IlMjJUaW1lJTIyJTNBJTIyMDAwMS0wMS0wMVQwMCUzQTAwJTNBMDBaJTIyJTJDJTIyVmFsaWQlMjIlM0FmYWxzZSU3RCUyQyUyMnVuZGVybHlpbmdfdGlja2VyJTIyJTNBJTIyQSUyMiUyQyUyMnRpY2tlciUyMiUzQSUyMk8lM0FBMjIwNTIwQzAwMTEwMDAwJTIyJTJDJTIyZXhwaXJhdGlvbl9kYXRlJTIyJTNBJTIyMjAyMi0wNS0yMFQwMCUzQTAwJTNBMDBaJTIyJTJDJTIyc3RyaWtlX3ByaWNlJTIyJTNBMTEwJTJDJTIyY2ZpJTIyJTNBJTIyT0NBU1BTJTIyJTJDJTIyY29udHJhY3RfdHlwZSUyMiUzQSUyMmNhbGwlMjIlMkMlMjJleGVyY2lzZV9zdHlsZSUyMiUzQSUyMmFtZXJpY2FuJTIyJTJDJTIycHJpbWFyeV9leGNoYW5nZSUyMiUzQSU3QiUyMlN0cmluZyUyMiUzQSUyMkJBVE8lMjIlMkMlMjJWYWxpZCUyMiUzQXRydWUlN0QlMkMlMjJzaGFyZXNfcGVyX2NvbnRyYWN0JTIyJTNBMTAwJTJDJTIyYWRkaXRpb25hbF91bmRlcmx5aW5ncyUyMiUzQSUyMm51bGwlMjIlN0QmYXM9JmNvbnRyYWN0X3R5cGU9Y2FsbCZsaW1pdD0xMCZzb3J0PXRpY2tlcg",
   587  	"results": [
   588  ` + indent(true, contract1, "\t\t") + `,
   589  ` + indent(true, contract2, "\t\t") + `
   590  	]
   591  }`
   592  
   593  	registerResponder("https://api.polygon.io/v3/reference/options/contracts?contract_type=call", expectedResponse)
   594  	registerResponder("https://api.polygon.io/v3/reference/options/contracts?cursor=YXA9JTdCJTIySUQlMjIlM0ElMjIyNzI2MTY3OTUxMjgzOTI1NTI5JTIyJTJDJTIyU3RhcnREYXRlVXRjJTIyJTNBJTdCJTIyVGltZSUyMiUzQSUyMjIwMjEtMDktMjFUMDAlM0EwMCUzQTAwWiUyMiUyQyUyMlZhbGlkJTIyJTNBdHJ1ZSU3RCUyQyUyMkVuZERhdGVVdGMlMjIlM0ElN0IlMjJUaW1lJTIyJTNBJTIyMDAwMS0wMS0wMVQwMCUzQTAwJTNBMDBaJTIyJTJDJTIyVmFsaWQlMjIlM0FmYWxzZSU3RCUyQyUyMnVuZGVybHlpbmdfdGlja2VyJTIyJTNBJTIyQSUyMiUyQyUyMnRpY2tlciUyMiUzQSUyMk8lM0FBMjIwNTIwQzAwMTEwMDAwJTIyJTJDJTIyZXhwaXJhdGlvbl9kYXRlJTIyJTNBJTIyMjAyMi0wNS0yMFQwMCUzQTAwJTNBMDBaJTIyJTJDJTIyc3RyaWtlX3ByaWNlJTIyJTNBMTEwJTJDJTIyY2ZpJTIyJTNBJTIyT0NBU1BTJTIyJTJDJTIyY29udHJhY3RfdHlwZSUyMiUzQSUyMmNhbGwlMjIlMkMlMjJleGVyY2lzZV9zdHlsZSUyMiUzQSUyMmFtZXJpY2FuJTIyJTJDJTIycHJpbWFyeV9leGNoYW5nZSUyMiUzQSU3QiUyMlN0cmluZyUyMiUzQSUyMkJBVE8lMjIlMkMlMjJWYWxpZCUyMiUzQXRydWUlN0QlMkMlMjJzaGFyZXNfcGVyX2NvbnRyYWN0JTIyJTNBMTAwJTJDJTIyYWRkaXRpb25hbF91bmRlcmx5aW5ncyUyMiUzQSUyMm51bGwlMjIlN0QmYXM9JmNvbnRyYWN0X3R5cGU9Y2FsbCZsaW1pdD0xMCZzb3J0PXRpY2tlcg", "{}")
   595  	iter := c.ListOptionsContracts(context.Background(), models.ListOptionsContractsParams{}.WithContractType("call"))
   596  
   597  	// iter creation
   598  	assert.Nil(t, iter.Err())
   599  	assert.NotNil(t, iter.Item())
   600  
   601  	// first item
   602  	assert.True(t, iter.Next())
   603  	assert.Nil(t, iter.Err())
   604  	var expect1 models.OptionsContract
   605  	err := json.Unmarshal([]byte(contract1), &expect1)
   606  	assert.Nil(t, err)
   607  	assert.Equal(t, expect1, iter.Item())
   608  
   609  	// second item
   610  	assert.True(t, iter.Next())
   611  	assert.Nil(t, iter.Err())
   612  	var expect2 models.OptionsContract
   613  	err = json.Unmarshal([]byte(contract2), &expect2)
   614  	assert.Nil(t, err)
   615  	assert.Equal(t, expect2, iter.Item())
   616  
   617  	// end of list
   618  	assert.False(t, iter.Next())
   619  	assert.Nil(t, iter.Err())
   620  }