sample code
This commit is contained in:
@@ -0,0 +1,9 @@
|
||||
name: Dafter Quote
|
||||
description: Provides quotes for a security, ETF or an option.
|
||||
core: 8.x
|
||||
type: module
|
||||
package: Daftar
|
||||
core_version_requirement: ^8 || ^9
|
||||
version: 1.0.0
|
||||
dependencies:
|
||||
- daftar_stock_api:daftar_stock_api
|
||||
@@ -0,0 +1,35 @@
|
||||
daftar_quote.options:
|
||||
path: '/quote/options'
|
||||
defaults:
|
||||
_title: 'Options Quote'
|
||||
_controller: '\Drupal\daftar_quote\Controller\OptionsController::quote'
|
||||
requirements:
|
||||
_access: 'TRUE'
|
||||
|
||||
daftar_quote.v2.options.contracts:
|
||||
path: '/v2/option/contracts/{symbol}/{type}/{expiration_date}'
|
||||
defaults:
|
||||
_title: 'Options Quote'
|
||||
_controller: '\Drupal\daftar_quote\Controller\OptionsController::v2_contracts'
|
||||
requirements:
|
||||
_access: 'TRUE'
|
||||
symbol: '[A-Z]{1,5}'
|
||||
type: 'calls|puts'
|
||||
expiration_date: '\d{4}-\d{2}-\d{2}'
|
||||
|
||||
daftar_quote.v2.options.contract:
|
||||
path: '/v2/option/contracts/{contract_symbol}'
|
||||
defaults:
|
||||
_title: 'Option Contract'
|
||||
_controller: '\Drupal\daftar_quote\Controller\OptionsController::v2_contract'
|
||||
requirements:
|
||||
_access: 'TRUE'
|
||||
#contract_symbol: '[A-Z]{1,5}\d{6}(P|C)\d{8}'
|
||||
|
||||
daftar_quote.v2.options.parse_contract_symbol:
|
||||
path: '/v2/option/contracts/parse'
|
||||
defaults:
|
||||
_title: 'Option Contract Parse'
|
||||
_controller: '\Drupal\daftar_quote\Controller\OptionsController::v2_parse_contract_symbol'
|
||||
requirements:
|
||||
_access: 'TRUE'
|
||||
@@ -0,0 +1,292 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\daftar_quote\Controller;
|
||||
|
||||
use DateTime;
|
||||
use Drupal\Core\Controller\ControllerBase;
|
||||
use Drupal\Core\Site\Settings;
|
||||
use Drupal\daftar_stock_api\Exception\StockApiException;
|
||||
use Drupal\daftar_stock_api\Service\YahooApiService;
|
||||
use Drupal\daftar_stock_api\Service\YahooParserService;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
use Symfony\Component\HttpFoundation\JsonResponse;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
|
||||
/**
|
||||
* Provides callback methods used for launching modals with content form.
|
||||
* @package Drupal\daftar_content\Controller
|
||||
*/
|
||||
class OptionsController extends ControllerBase {
|
||||
const SETTINGS_KEY_OPTIONS_TOKEN = 'daftar_quote_options_token';
|
||||
const CONTRACT_SYMBOL_PATTERN = '/^([A-Z]{1,5})(\d{6})([PC])(\d{8})$/';
|
||||
const CONTRACT_SYMBOL_FD_PATTERN = '/^-?([A-Z]{1,5})(\d{6})([PC])(\d{1,4}([.]\d{1,2})?)$/';
|
||||
// Tran Date Contact Symbol QT PPS Total
|
||||
const CONTRACT_SYMBOL_FD_PATTERN2 = '/^(\d{2}\/\d{2}\/\d{4})[ ]+YOU (SOLD|BOUGHT) (OPENING|CLOSING) TRANSACTION[ ]+-?([A-Z]{1,5})(\d{6})([PC])(\d{1,4}[\.]?\d{0,2})[ ]+(-?\d{1,4})[ ]+\$(\d{1,4}[\.]?\d{0,4})[ ]+\$(-?\d+[,]?\d{0,3}[\.]?\d{0,2})[ ]+\$(\d{1,3}[\.]?\d{0,2})[ ]+\$(\d{1,3}[\.]?\d{0,2}).*$/';
|
||||
// Tran Date Contact Symbol QT PPS Total
|
||||
const CONTRACT_SYMBOL_FD_PATTERN2B = '/^(\d{2}\/\d{2}\/\d{4})YOU (SOLD|BOUGHT) (OPENING|CLOSING) TRANSACTION-?([A-Z]{1,5})(\d{6})([PC])(\d{1,4}[\.]?\d{0,2})(-?\d{1,4})\$(\d{1,4}[\.]?\d{0,4})\$(-?\d+[,]?\d{0,3}[\.]?\d{0,2})\$(\d{1,3}[\.]?\d{0,2})\$(\d{1,3}[\.]?\d{0,2}).*$/';
|
||||
const CONTRACT_SYMBOL_TDA_PATTERN = '/^(Sold|Bought) (\d+) ([A-Z]{1,5}) ([A-Z][a-z]{2} \d{1,2} \d{4}) (\d{1,4}([.]\d{1,2})?) (Call|Put) @ (\d{1,4}([.]\d{1,2})?)$/';
|
||||
/**
|
||||
* @var \Drupal\daftar_stock_api\Service\YahooParserService
|
||||
*/
|
||||
protected YahooParserService $yahooParser;
|
||||
|
||||
/**
|
||||
* @var \Drupal\daftar_stock_api\Service\YahooApiService
|
||||
*/
|
||||
protected YahooApiService $yahooApi;
|
||||
|
||||
/**
|
||||
* OptionsController constructor.
|
||||
*
|
||||
* @param YahooParserService $yahoo_parser_service
|
||||
* @param \Drupal\daftar_stock_api\Service\YahooApiService $yahoo_api_service
|
||||
*/
|
||||
public function __construct(YahooParserService $yahoo_parser_service, YahooApiService $yahoo_api_service) {
|
||||
$this->yahooParser = $yahoo_parser_service;
|
||||
$this->yahooApi = $yahoo_api_service;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function create(ContainerInterface $container): OptionsController {
|
||||
return new static(
|
||||
$container->get('daftar.stock_api.yahoo_parser'),
|
||||
$container->get('daftar.stock_api.yahoo_api')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $symbol
|
||||
* @param string $type
|
||||
* @param string $expiration_date
|
||||
* @param Request $request
|
||||
*
|
||||
* @return JsonResponse
|
||||
*/
|
||||
public function v2_contracts(string $symbol, string $type, string $expiration_date, Request $request): JsonResponse {
|
||||
$tokenCheck = $this->checkToken($request);
|
||||
if ($tokenCheck) {
|
||||
return $tokenCheck;
|
||||
}
|
||||
|
||||
$strike = $request->get('strike');
|
||||
return $this->v2_fetchContracts($symbol, $type, $expiration_date, $strike);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $contract_symbol
|
||||
* @param Request $request
|
||||
*
|
||||
* @return JsonResponse
|
||||
*/
|
||||
public function v2_contract(string $contract_symbol, Request $request): JsonResponse {
|
||||
$tokenCheck = $this->checkToken($request);
|
||||
if ($tokenCheck) {
|
||||
return $tokenCheck;
|
||||
}
|
||||
|
||||
if (preg_match(self::CONTRACT_SYMBOL_PATTERN, $contract_symbol, $matches)) {
|
||||
$date = DateTime::createFromFormat('ymd', $matches[2]);
|
||||
$type = ($matches[3] === 'P') ? 'puts' : 'calls';
|
||||
$strike = intval($matches[4])/1000;
|
||||
return $this->v2_fetchContracts($matches[1], $type, $date->format('Y-m-d'), $strike);
|
||||
}
|
||||
|
||||
return new JsonResponse([
|
||||
'error' => TRUE,
|
||||
'message' => $this->t('Invalid contract symbol.'),
|
||||
], Response::HTTP_BAD_REQUEST);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $contract_symbol
|
||||
* @param Request $request
|
||||
*
|
||||
* @return JsonResponse
|
||||
*/
|
||||
public function v2_parse_contract_symbol(Request $request): JsonResponse {
|
||||
$tokenCheck = $this->checkToken($request);
|
||||
if ($tokenCheck) {
|
||||
return $tokenCheck;
|
||||
}
|
||||
|
||||
$parsed = [];
|
||||
$contractSymbol = $request->request->get('contract_symbol');
|
||||
//$contractSymbol = $request->get('contract_symbol');
|
||||
if (preg_match(self::CONTRACT_SYMBOL_PATTERN, $contractSymbol, $matches)) {
|
||||
$date = DateTime::createFromFormat('ymd', $matches[2]);
|
||||
$parsed = [
|
||||
'symbol' => $matches[1],
|
||||
'expiration_date' => $date->format('m/d/Y'),
|
||||
'type' => ($matches[3] === 'P') ? 'PUT' : 'CALL',
|
||||
'strike' => intval($matches[4])/1000,
|
||||
'account' => '',
|
||||
];
|
||||
}
|
||||
elseif (preg_match(self::CONTRACT_SYMBOL_FD_PATTERN, $contractSymbol, $matches)) {
|
||||
$date = DateTime::createFromFormat('ymd', $matches[2]);
|
||||
$parsed = [
|
||||
'symbol' => $matches[1],
|
||||
'expiration_date' => $date->format('m/d/Y'),
|
||||
'type' => ($matches[3] === 'P') ? 'PUT' : 'CALL',
|
||||
'strike' => $matches[4],
|
||||
'account' => 'FD',
|
||||
];
|
||||
}
|
||||
elseif (preg_match(self::CONTRACT_SYMBOL_FD_PATTERN2, $contractSymbol, $matches)
|
||||
|| preg_match(self::CONTRACT_SYMBOL_FD_PATTERN2B, $contractSymbol, $matches)) {
|
||||
$date = DateTime::createFromFormat('ymd', $matches[5]);
|
||||
$action = substr($matches[2], 0, 1) . '2';
|
||||
$action .= ($matches[3] === 'CLOSING') ? 'X' : 'O';
|
||||
|
||||
$parsed = [
|
||||
'tran_date' => $matches[1],
|
||||
'action' => $action,
|
||||
'symbol' => $matches[4],
|
||||
'expiration_date' => $date->format('m/d/Y'),
|
||||
'type' => ($matches[6] === 'P') ? 'PUT' : 'CALL',
|
||||
'strike' => $matches[7],
|
||||
'quantity' => $matches[8],
|
||||
'account' => 'FD2',
|
||||
'price' => $matches[9],
|
||||
'comm' => $matches[11],
|
||||
'fees' => $matches[12]
|
||||
];
|
||||
}
|
||||
elseif (preg_match(self::CONTRACT_SYMBOL_TDA_PATTERN, $contractSymbol, $matches)) {
|
||||
$date = DateTime::createFromFormat('M d Y', $matches[4]);
|
||||
$parsed = [
|
||||
'symbol' => $matches[3],
|
||||
'expiration_date' => $date->format('m/d/Y'),
|
||||
'type' => ($matches[7] === 'Put') ? 'PUT' : 'CALL',
|
||||
'strike' => $matches[5],
|
||||
'account' => 'TDA',
|
||||
'action' => ($matches[1] === 'Sold') ? 'S2O' : 'B2O',
|
||||
'quantity' => $matches[2],
|
||||
'price' => $matches[8],
|
||||
];
|
||||
}
|
||||
|
||||
if ($parsed) {
|
||||
$parsed['contract'] = NULL;
|
||||
try {
|
||||
$type = ($parsed['type'] == 'CALL') ? 'calls' : 'puts';
|
||||
$contractData = $this->yahooApi->getOptionContract(
|
||||
$parsed['symbol'], $parsed['expiration_date'], $type, $parsed['strike']
|
||||
);
|
||||
if (!$contractData['error']) {
|
||||
$parsed['contract'] = $contractData['contents'];
|
||||
}
|
||||
|
||||
} catch (StockApiException $e) {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
return new JsonResponse([
|
||||
'error' => FALSE,
|
||||
'message' => '',
|
||||
'contents' => $parsed,
|
||||
], Response::HTTP_OK);
|
||||
}
|
||||
else {
|
||||
return new JsonResponse([
|
||||
'error' => TRUE,
|
||||
'message' => $this->t('Invalid or missing contract symbol.'),
|
||||
'contract_symbol' => $contractSymbol,
|
||||
], Response::HTTP_BAD_REQUEST);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Request $request
|
||||
* @return JsonResponse
|
||||
*/
|
||||
public function quote(Request $request): JsonResponse {
|
||||
$tokenCheck = $this->checkToken($request);
|
||||
if ($tokenCheck) {
|
||||
return $tokenCheck;
|
||||
}
|
||||
|
||||
$symbol = $request->get('symbol');
|
||||
if (!$symbol) {
|
||||
return new JsonResponse([
|
||||
'error' => TRUE,
|
||||
'message' => $this->t('Missing symbol.'),
|
||||
], Response::HTTP_BAD_REQUEST);
|
||||
}
|
||||
|
||||
$price = $this->yahooParser->getPrice($symbol);
|
||||
if ($price) {
|
||||
return new JsonResponse([
|
||||
'error' => FALSE,
|
||||
'message' => 'success',
|
||||
'price' => $price,
|
||||
], Response::HTTP_OK);
|
||||
}
|
||||
|
||||
return new JsonResponse([
|
||||
'error' => TRUE,
|
||||
'message' => $this->t('Unable to parse price.'),
|
||||
], Response::HTTP_INTERNAL_SERVER_ERROR);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $symbol
|
||||
* @param string $type
|
||||
* @param string $expiration_date
|
||||
* @param $strike
|
||||
*
|
||||
* @return \Symfony\Component\HttpFoundation\JsonResponse
|
||||
*/
|
||||
private function v2_fetchContracts(string $symbol, string $type, string $expiration_date, $strike = ""): JsonResponse {
|
||||
if ($type == 'CALL') {
|
||||
$type == 'calls';
|
||||
}
|
||||
if ($type == 'PUT') {
|
||||
$type == 'puts';
|
||||
}
|
||||
|
||||
try {
|
||||
if ($strike) {
|
||||
$data = $this->yahooApi->getOptionContract($symbol, $expiration_date, $type, $strike);
|
||||
}
|
||||
else {
|
||||
$data = $this->yahooApi->getOptionContracts($symbol, $expiration_date, $type);
|
||||
}
|
||||
return new JsonResponse($data, Response::HTTP_OK);
|
||||
}
|
||||
catch (StockApiException $e) {
|
||||
//do nothing
|
||||
}
|
||||
|
||||
return new JsonResponse([
|
||||
'error' => TRUE,
|
||||
'message' => $this->t('Error occurred while finding contract.'),
|
||||
], Response::HTTP_INTERNAL_SERVER_ERROR);
|
||||
}
|
||||
|
||||
private function checkToken(Request $request): ?JsonResponse {
|
||||
$optionsToken = Settings::get(static::SETTINGS_KEY_OPTIONS_TOKEN, '');
|
||||
if (!$optionsToken) {
|
||||
return new JsonResponse([
|
||||
'error' => TRUE,
|
||||
'message' => $this->t('Token setup has not been completed.'),
|
||||
], Response::HTTP_INTERNAL_SERVER_ERROR);
|
||||
}
|
||||
|
||||
$receivedToken = $request->get('token');
|
||||
if ($receivedToken !== $optionsToken) {
|
||||
return new JsonResponse([
|
||||
'error' => TRUE,
|
||||
'message' => $this->t('Invalid token.'),
|
||||
], Response::HTTP_FORBIDDEN);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user