Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add test for stocks->quotes, reformatted option_chains, fixed typo #8

Merged
merged 3 commits into from
Jul 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/Endpoints/Responses/Indices/Quote.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,10 @@ class Quote

// The difference in price in dollars (or the index's native currency if different from dollars) compared to the
// closing price of the previous day.
public float $change;
public float|null $change;

// The difference in price in percent compared to the closing price of the previous day.
public float $change_percent;
public float|null $change_percent;

// The 52-week high for the index.
public float|null $fifty_two_week_high = null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
use Carbon\Carbon;
use MarketDataApp\Enums\Side;

class OptionChain
class OptionChainStrike
{

public function __construct(
Expand Down
7 changes: 4 additions & 3 deletions src/Endpoints/Responses/Options/OptionChains.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ class OptionChains
// Time of the previous quote if there is no data in the requested period, but there is data in a previous period.
public Carbon $prev_time;

/** @var OptionChain[] $option_chains */
/** @var array[array[OptionChainStrike[]]] $option_chains */
public array $option_chains = [];

public function __construct(object $response)
Expand All @@ -28,10 +28,11 @@ public function __construct(object $response)
switch ($this->status) {
case 'ok':
for ($i = 0; $i < count($response->optionSymbol); $i++) {
$this->option_chains[] = new OptionChain(
$expiration = Carbon::parse($response->expiration[$i]);
$this->option_chains[$expiration->toDateString()][] = new OptionChainStrike(
option_symbol: $response->optionSymbol[$i],
underlying: $response->underlying[$i],
expiration: Carbon::parse($response->expiration[$i]),
expiration: $expiration,
side: Side::from($response->side[$i]),
strike: $response->strike[$i],
first_traded: Carbon::parse($response->firstTraded[$i]),
Expand Down
4 changes: 2 additions & 2 deletions src/Endpoints/Stocks.php
Original file line number Diff line number Diff line change
Expand Up @@ -167,12 +167,12 @@ public function quote(string $symbol, bool $fifty_two_week = false): Quote
*
* @throws \Throwable
*/
public function quotes(array $symbols, bool $fifty_two_week = false): Quotes|BulkQuotes
public function quotes(array $symbols, bool $fifty_two_week = false): Quotes
{
// Execute standard quotes in parallel
$calls = [];
foreach ($symbols as $symbol) {
$calls[] = ["/stocks/quotes/$symbol", ['52week' => $fifty_two_week]];
$calls[] = [self::BASE_URL . "quotes/$symbol", ['52week' => $fifty_two_week]];
}

return new Quotes($this->client->executeInParallel($calls));
Expand Down
2 changes: 1 addition & 1 deletion src/Enums/Range.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,6 @@ enum Range: string
{

case IN_THE_MONEY = 'itm';
case OUT_THE_MONEY = 'otm';
case OUT_OF_THE_MONEY = 'otm';
case ALL = 'all';
}
59 changes: 31 additions & 28 deletions tests/Integration/OptionsTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
use MarketDataApp\Client;
use MarketDataApp\Endpoints\Responses\Options\Expirations;
use MarketDataApp\Endpoints\Responses\Options\Lookup;
use MarketDataApp\Endpoints\Responses\Options\OptionChain;
use MarketDataApp\Endpoints\Responses\Options\OptionChainStrike;
use MarketDataApp\Endpoints\Responses\Options\OptionChains;
use MarketDataApp\Endpoints\Responses\Options\Quote;
use MarketDataApp\Endpoints\Responses\Options\Quotes;
Expand Down Expand Up @@ -104,34 +104,37 @@ public function testOptionChain_success()
// Verify that the response is an object of the correct type.
$this->assertInstanceOf(OptionChains::class, $response);
$this->assertNotEmpty($response->option_chains);
$option_chain = array_pop($response->option_chains);
$this->assertNotEmpty($option_chain);

// Verify each item in the response is an object of the correct type and has the correct values.
$this->assertInstanceOf(OptionChain::class, $response->option_chains[0]);
$this->assertEquals('string', gettype($response->option_chains[0]->option_symbol));
$this->assertEquals('string', gettype($response->option_chains[0]->underlying));
$this->assertInstanceOf(Carbon::class, $response->option_chains[0]->expiration);
$this->assertInstanceOf(Side::class, $response->option_chains[0]->side);
$this->assertEquals('double', gettype($response->option_chains[0]->strike));
$this->assertInstanceOf(Carbon::class, $response->option_chains[0]->first_traded);
$this->assertEquals('integer', gettype($response->option_chains[0]->dte));
$this->assertInstanceOf(Carbon::class, $response->option_chains[0]->updated);
$this->assertEquals('double', gettype($response->option_chains[0]->bid));
$this->assertEquals('integer', gettype($response->option_chains[0]->bid_size));
$this->assertEquals('double', gettype($response->option_chains[0]->mid));
$this->assertEquals('double', gettype($response->option_chains[0]->ask));
$this->assertEquals('integer', gettype($response->option_chains[0]->ask_size));
$this->assertTrue(in_array(gettype($response->option_chains[0]->last), ['double', 'NULL']));
$this->assertEquals('integer', gettype($response->option_chains[0]->open_interest));
$this->assertEquals('integer', gettype($response->option_chains[0]->volume));
$this->assertEquals('boolean', gettype($response->option_chains[0]->in_the_money));
$this->assertEquals('double', gettype($response->option_chains[0]->intrinsic_value));
$this->assertEquals('double', gettype($response->option_chains[0]->extrinsic_value));
$this->assertEquals('double', gettype($response->option_chains[0]->implied_volatility));
$this->assertTrue(in_array(gettype($response->option_chains[0]->delta), ['double', 'NULL']));
$this->assertEquals('double', gettype($response->option_chains[0]->gamma));
$this->assertEquals('double', gettype($response->option_chains[0]->theta));
$this->assertEquals('double', gettype($response->option_chains[0]->vega));
$this->assertEquals('double', gettype($response->option_chains[0]->rho));
$this->assertEquals('double', gettype($response->option_chains[0]->underlying_price));
$option_strike = array_pop($option_chain);
$this->assertInstanceOf(OptionChainStrike::class, $option_strike);
$this->assertEquals('string', gettype($option_strike->option_symbol));
$this->assertEquals('string', gettype($option_strike->underlying));
$this->assertInstanceOf(Carbon::class, $option_strike->expiration);
$this->assertInstanceOf(Side::class, $option_strike->side);
$this->assertEquals('double', gettype($option_strike->strike));
$this->assertInstanceOf(Carbon::class, $option_strike->first_traded);
$this->assertEquals('integer', gettype($option_strike->dte));
$this->assertInstanceOf(Carbon::class, $option_strike->updated);
$this->assertEquals('double', gettype($option_strike->bid));
$this->assertEquals('integer', gettype($option_strike->bid_size));
$this->assertEquals('double', gettype($option_strike->mid));
$this->assertEquals('double', gettype($option_strike->ask));
$this->assertEquals('integer', gettype($option_strike->ask_size));
$this->assertTrue(in_array(gettype($option_strike->last), ['double', 'NULL']));
$this->assertEquals('integer', gettype($option_strike->open_interest));
$this->assertEquals('integer', gettype($option_strike->volume));
$this->assertEquals('boolean', gettype($option_strike->in_the_money));
$this->assertEquals('double', gettype($option_strike->intrinsic_value));
$this->assertEquals('double', gettype($option_strike->extrinsic_value));
$this->assertEquals('double', gettype($option_strike->implied_volatility));
$this->assertTrue(in_array(gettype($option_strike->delta), ['double', 'NULL']));
$this->assertEquals('double', gettype($option_strike->gamma));
$this->assertEquals('double', gettype($option_strike->theta));
$this->assertEquals('double', gettype($option_strike->vega));
$this->assertEquals('double', gettype($option_strike->rho));
$this->assertEquals('double', gettype($option_strike->underlying_price));
}
}
21 changes: 21 additions & 0 deletions tests/Integration/StocksTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,27 @@ public function testQuote_success()
$this->assertInstanceOf(Carbon::class, $response->updated);
}

public function testQuotes_success()
{
$response = $this->client->stocks->quotes(['AAPL']);

$this->assertInstanceOf(Quote::class, $response->quotes[0]);
$this->assertEquals('string', gettype($response->quotes[0]->status));
$this->assertEquals('string', gettype($response->quotes[0]->symbol));
$this->assertEquals('double', gettype($response->quotes[0]->ask));
$this->assertEquals('integer', gettype($response->quotes[0]->ask_size));
$this->assertEquals('double', gettype($response->quotes[0]->bid));
$this->assertEquals('integer', gettype($response->quotes[0]->bid_size));
$this->assertEquals('double', gettype($response->quotes[0]->mid));
$this->assertEquals('double', gettype($response->quotes[0]->last));
$this->assertTrue(in_array(gettype($response->quotes[0]->change), ['double', 'NULL']));
$this->assertTrue(in_array(gettype($response->quotes[0]->change_percent), ['double', 'NULL']));
$this->assertNull($response->quotes[0]->fifty_two_week_high);
$this->assertNull($response->quotes[0]->fifty_two_week_low);
$this->assertEquals('integer', gettype($response->quotes[0]->volume));
$this->assertInstanceOf(Carbon::class, $response->quotes[0]->updated);
}

/**
* @throws \Throwable
*/
Expand Down
114 changes: 57 additions & 57 deletions tests/Unit/OptionsTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
use MarketDataApp\Client;
use MarketDataApp\Endpoints\Responses\Options\Expirations;
use MarketDataApp\Endpoints\Responses\Options\Lookup;
use MarketDataApp\Endpoints\Responses\Options\OptionChain;
use MarketDataApp\Endpoints\Responses\Options\OptionChainStrike;
use MarketDataApp\Endpoints\Responses\Options\OptionChains;
use MarketDataApp\Endpoints\Responses\Options\Quote;
use MarketDataApp\Endpoints\Responses\Options\Quotes;
Expand Down Expand Up @@ -212,77 +212,77 @@ public function testOptionChain_success()
{
$mocked_response = [
's' => 'ok',
'optionSymbol' => ['AAPL230616C00060000', 'AAPL230616C00065000'],
'underlying' => ['AAPL', 'AAPL'],
'expiration' => [1686945600, 1686945600],
'side' => ['call', 'call'],
'strike' => [60, 65],
'firstTraded' => [1617197400, 1616592600],
'dte' => [26, 26],
'updated' => [1684702875, 1684702875],
'bid' => [114.1, 108.6],
'bidSize' => [90, 90],
'mid' => [115.5, 110.38],
'ask' => [116.9, 112.15],
'askSize' => [90, 90],
'last' => [115, 107.82],
'openInterest' => [21957, 3012],
'volume' => [0, 0],
'inTheMoney' => [true, true],
'intrinsicValue' => [115.13, 110.13],
'extrinsicValue' => [0.37, 0.25],
'underlyingPrice' => [175.13, 175.13],
'iv' => [1.629, 1.923],
'delta' => [1, 1],
'gamma' => [0, 0],
'theta' => [-0.009, -0.009],
'vega' => [0, 0],
'rho' => [0.046, 0.05]
'optionSymbol' => ['AAPL230616C00060000', 'AAPL230616C00065000', 'AAPL230616C00075000'],
'underlying' => ['AAPL', 'AAPL', 'AAPL'],
'expiration' => [1686945600, 1686945600, 1687045600],
'side' => ['call', 'call', 'call'],
'strike' => [60, 65, 60],
'firstTraded' => [1617197400, 1616592600, 1616602600],
'dte' => [26, 26, 33],
'updated' => [1684702875, 1684702875, 1684702876],
'bid' => [114.1, 108.6, 120.5],
'bidSize' => [90, 90, 95],
'mid' => [115.5, 110.38, 120.5],
'ask' => [116.9, 112.15, 118.5],
'askSize' => [90, 90, 95],
'last' => [115, 107.82, 119.3],
'openInterest' => [21957, 3012, 5000],
'volume' => [0, 0, 100],
'inTheMoney' => [true, true, true],
'intrinsicValue' => [115.13, 110.13, 119.13],
'extrinsicValue' => [0.37, 0.25, 0.13],
'underlyingPrice' => [175.13, 175.13, 118.5],
'iv' => [1.629, 1.923, 1.753],
'delta' => [1, 1, -0.95],
'gamma' => [0, 0, 0.3],
'theta' => [-0.009, -0.009, -.3],
'vega' => [0, 0, 0.3],
'rho' => [0.046, 0.05, 0.4]
];
$this->setMockResponses([new Response(200, [], json_encode($mocked_response))]);

$response = $this->client->options->option_chain(
symbol: 'AAPL',
expiration: '2025-01-17',
side: Side::CALL,
);

// Verify that the response is an object of the correct type.
$this->assertInstanceOf(OptionChains::class, $response);
$this->assertCount(2, $response->option_chains);
$this->assertCount(2, $response->option_chains['2023-06-16']);
$this->assertCount(1, $response->option_chains['2023-06-17']);

// Verify each item in the response is an object of the correct type and has the correct values.
for ($i = 0; $i < count($response->option_chains); $i++) {
$this->assertInstanceOf(OptionChain::class, $response->option_chains[$i]);
$this->assertEquals($mocked_response['optionSymbol'][$i], $response->option_chains[$i]->option_symbol);
$this->assertEquals($mocked_response['underlying'][$i], $response->option_chains[$i]->underlying);
foreach (array_merge(...array_values($response->option_chains)) as $i => $option_strike) {
$this->assertInstanceOf(OptionChainStrike::class, $option_strike);
$this->assertEquals($mocked_response['optionSymbol'][$i], $option_strike->option_symbol);
$this->assertEquals($mocked_response['underlying'][$i], $option_strike->underlying);
$this->assertEquals(Carbon::parse($mocked_response['expiration'][$i]),
$response->option_chains[$i]->expiration);
$this->assertEquals(Side::from($mocked_response['side'][$i]), $response->option_chains[$i]->side);
$this->assertEquals($mocked_response['strike'][$i], $response->option_chains[$i]->strike);
$option_strike->expiration);
$this->assertEquals(Side::from($mocked_response['side'][$i]), $option_strike->side);
$this->assertEquals($mocked_response['strike'][$i], $option_strike->strike);
$this->assertEquals(Carbon::parse($mocked_response['firstTraded'][$i]),
$response->option_chains[$i]->first_traded);
$this->assertEquals($mocked_response['dte'][$i], $response->option_chains[$i]->dte);
$this->assertEquals(Carbon::parse($mocked_response['updated'][$i]), $response->option_chains[$i]->updated);
$this->assertEquals($mocked_response['bid'][$i], $response->option_chains[$i]->bid);
$this->assertEquals($mocked_response['bidSize'][$i], $response->option_chains[$i]->bid_size);
$this->assertEquals($mocked_response['mid'][$i], $response->option_chains[$i]->mid);
$this->assertEquals($mocked_response['ask'][$i], $response->option_chains[$i]->ask);
$this->assertEquals($mocked_response['askSize'][$i], $response->option_chains[$i]->ask_size);
$this->assertEquals($mocked_response['last'][$i], $response->option_chains[$i]->last);
$this->assertEquals($mocked_response['openInterest'][$i], $response->option_chains[$i]->open_interest);
$this->assertEquals($mocked_response['volume'][$i], $response->option_chains[$i]->volume);
$this->assertEquals($mocked_response['inTheMoney'][$i], $response->option_chains[$i]->in_the_money);
$this->assertEquals($mocked_response['intrinsicValue'][$i], $response->option_chains[$i]->intrinsic_value);
$this->assertEquals($mocked_response['extrinsicValue'][$i], $response->option_chains[$i]->extrinsic_value);
$this->assertEquals($mocked_response['iv'][$i], $response->option_chains[$i]->implied_volatility);
$this->assertEquals($mocked_response['delta'][$i], $response->option_chains[$i]->delta);
$this->assertEquals($mocked_response['gamma'][$i], $response->option_chains[$i]->gamma);
$this->assertEquals($mocked_response['theta'][$i], $response->option_chains[$i]->theta);
$this->assertEquals($mocked_response['vega'][$i], $response->option_chains[$i]->vega);
$this->assertEquals($mocked_response['rho'][$i], $response->option_chains[$i]->rho);
$option_strike->first_traded);
$this->assertEquals($mocked_response['dte'][$i], $option_strike->dte);
$this->assertEquals(Carbon::parse($mocked_response['updated'][$i]), $option_strike->updated);
$this->assertEquals($mocked_response['bid'][$i], $option_strike->bid);
$this->assertEquals($mocked_response['bidSize'][$i], $option_strike->bid_size);
$this->assertEquals($mocked_response['mid'][$i], $option_strike->mid);
$this->assertEquals($mocked_response['ask'][$i], $option_strike->ask);
$this->assertEquals($mocked_response['askSize'][$i], $option_strike->ask_size);
$this->assertEquals($mocked_response['last'][$i], $option_strike->last);
$this->assertEquals($mocked_response['openInterest'][$i], $option_strike->open_interest);
$this->assertEquals($mocked_response['volume'][$i], $option_strike->volume);
$this->assertEquals($mocked_response['inTheMoney'][$i], $option_strike->in_the_money);
$this->assertEquals($mocked_response['intrinsicValue'][$i], $option_strike->intrinsic_value);
$this->assertEquals($mocked_response['extrinsicValue'][$i], $option_strike->extrinsic_value);
$this->assertEquals($mocked_response['iv'][$i], $option_strike->implied_volatility);
$this->assertEquals($mocked_response['delta'][$i], $option_strike->delta);
$this->assertEquals($mocked_response['gamma'][$i], $option_strike->gamma);
$this->assertEquals($mocked_response['theta'][$i], $option_strike->theta);
$this->assertEquals($mocked_response['vega'][$i], $option_strike->vega);
$this->assertEquals($mocked_response['rho'][$i], $option_strike->rho);
$this->assertEquals($mocked_response['underlyingPrice'][$i],
$response->option_chains[$i]->underlying_price);
$option_strike->underlying_price);
}
}

Expand Down