0
\$\begingroup\$

Goal

This is very basic beginner script, only for prototyping, probably never to reach alpha/beta prototyping/production, is being designed/tested for performance. Its performance quality might be somewhere around 1-2% now and at least requires another 60-70% for reaching a reasonable version.

Function

It scrapes equity data from an API, does basic statistical analytics, and returns daily price targets for ~8000 equities in NYSE, NASDAQ and CBOE markets in HTML forms.

Reviewing

For reviewing, this class extends the main class and generates an HTML string for user interface. You can also view the entire codes in this link.

It works okay, however would you be so kind and review it (maybe for performance) and maybe list your changes/to be changed to, if possible?

HTMLviewEQ class

date_default_timezone_set("America/New_York"); ini_set('max_execution_time', 0); ini_set('memory_limit', '-1'); set_time_limit(0); require_once __DIR__ . "/HTMLviewEQ.php"; class HTMLviewEQ extends EQ implements ConstEQ { /** * * @return a large HTML string of base article content including meta, abstract and written analysis */ public static function getBaseHTML($array, $page_id, $class_obj) { /** *@var is the current datatime */ $dt = new \DateTime('now'); $dt = $dt->format('Y-m-d H:i:s'); /** *@var is the equity symbol: AAPL, AMD */ $symb = $array["quote"]["symbol"]; /** *@var is the full name of public company */ $comp = $array["quote"]["companyName"]; /** *@var is the name of sector: Technology, Healthcare */ $sect = $array["quote"]["sector"]; /** *@var is the name of exchange market: New York Stock Exchange, CBOE, NASDAQ */ $mark = $array["quote"]["primaryExchange"]; /** *@var is the first date in chart array, which is the oldest date */ $fd = $array["chart"][0]["date"]; /** *@var is the last date in chart array, which is the newest date */ $ld = array_reverse($array["chart"])[0]["date"]; /** *@var is the article URL */ $url = ConstEQ::PROTOCOL . ConstEQ::DOMAIN . ConstEQ::SLASH . ConstEQ::DIR_URL_KEYWORD_1 . ConstEQ::SLASH . ConstEQ::DIR_URL_KEYWORD_2 . ConstEQ::SLASH . $page_id; /** *@var is a short meta for page about */ $page_about = $comp . ": Seven price sets are approximated for " . $symb . " lowest supports, " . $symb . " highest resistances and " . $symb . " equilibriums. Each price set is a forecast of daily equity price range of " . $symb . " and has a percentage indicator which shows " . $symb . " upward or downward trends in that session."; /** *@var is a short meta for page description */ $page_description = $symb . " - " . $comp . ": Average equilibrium share price forecasts are pretty important for " . $symb . " short/long trading and investing, " . $symb . " institutional trading, " . $symb . " portfolio management, " . $symb . " risk assessment, " . $symb . " algorithmic and automated trading, " . $symb . " buy/sell/hold decision makings, " . $symb . " day/swing trading, " . $symb . " put and call option forecasting, " . $symb . " volume estimating, " . $symb . " volatility approximating, " . $symb . " resistance and support evaluating, " . $symb . " stop loss computations, " . $symb . " sentiment analysis and " . $symb . " other quantitative analytics."; $wrap_symb = '<b class="br-2 b119 r1' . rand(20, 99) . '">' . $symb . '</b>'; /** *@var is a summary/highlight of article */ $article_highlight = $comp . ": Seven price sets are being approximated for " . $wrap_symb . " lowest supports, " . $wrap_symb . " average equilibriums and " . $wrap_symb . " highest resistances. Each set has a \"percentage\", which indicates that if " . $wrap_symb . " has been outperforming or downperforming during that day."; /** *@var is an abstract for the article */ $article_abstract = $wrap_symb . " - " . $comp . ": Equilibrium price is important for " . $wrap_symb . " institutional trading/investing, " . $wrap_symb . " retail trading/investing and other types of short/long positions. They provide supplementary perspectives to traders for " . $wrap_symb . " day/swing trading, " . $wrap_symb . " low/high frequency trading, " . $wrap_symb . " put/call option forecasting, " . $wrap_symb . " forward/reverse trading/investing and " . $wrap_symb . " algorithmic trading. Average equilibrium price is necessary for " . $wrap_symb . " Buy/Sell/Hold decision makings and " . $wrap_symb . " rating for analyst coverages and equity due diligence. They are also beneficial for " . $wrap_symb . " trading volume forecasting, " . $wrap_symb . " daily volatility approximating, " . $wrap_symb . " resistance and support evaluating, " . $wrap_symb . " stop loss calculations, among other quantitative advantages. Static charts cannot provide such information to trading and investing entities."; /** *@var is a legal warning for informing visitors */ $article_warning = "βš– All " . $symb . " information are connected to delayed 60-seconds data pipelines from version 1.0 API at https://api.iextrading.com/1.0/, in addition to other financial and economical data. All computations are automatic, currently independent of all news, sentiments, external parameters and internal corporate factors. This page is only an alpha prototype and is only updated a few times per hour based on our dynamic indices and latest quote scraped from that API. It may not be accessible at all times, and inadvertent or unknown inaccuracies exist. All information are provided under \"AT YOUR OWN FULL RISKS\" and \"NO LIABILITIES, UNDER NO CIRCUMSTANCES\" terms. Trade Safe and Happy Investing!"; /** *@var is a list of terms used in the articles */ $indicators = array( "Equilibrium" => $wrap_symb . " equilibrium is an average theoretical price, where both buy and sell flows of " . $wrap_symb . " are equal. It is good to be taken into account in near-term trading/investing decision makings.", "Sessions" => $wrap_symb . " data from " . sizeof($array["chart"]) . " days has been summarized here, each with eight price sets for " . $wrap_symb . ". The first set has the actual " . $wrap_symb . " market prices. The other seven sets are our estimated equilibrium prices for " . $wrap_symb . ". On the left, dynamic lowest supports of " . $wrap_symb . " have been displayed and on the right, you can see the dynamic highest resistances of " . $wrap_symb . ".", "Volatility" => "\"Low\" to \"extreme\" volatilities have been forced to our algorithms for computing " . $wrap_symb . " supports and resistances from set 1 to set 7, respectively.", "Percentage" => "The underneath \"percentage\" is an indicator of the difference in between the actual " . $wrap_symb . " and our estimated equilibrium prices for " . $wrap_symb . ".", "Supports" => "" . $wrap_symb . " dynamic supports have been approximated as a function of time.", "Resistances" => " " . $wrap_symb . " dynamic resistances have been also approximated as a function of time.", "Narrow Supports Range" => "If 7 dynamic supports of " . $wrap_symb . " are very close, it might indicate: (a) there may not have been much trading/investing actions on " . $wrap_symb . "; OR (b) " . $wrap_symb . " may have solid block traders/investors; OR (c) " . $wrap_symb . " might have had a low-risk and low-return session; AND (d) other similar analyses can be extracted from.", "Distant Supports Range" => "If 7 dynamic supports of " . $wrap_symb . " are very scattered, it might indicate: (a) there might have been much sophisticated trading actions on " . $wrap_symb . "; OR (b) " . $wrap_symb . " might have had adept traders in that session; OR (c) " . $wrap_symb . " may have had a high-risk and high-return session; AND (d) other similar analyses can be obtained.", "Narrow Resistances Range" => "If 7 dynamic resistances of " . $wrap_symb . " are very close, it may suggest outcomes such as: (a) " . $wrap_symb . " holds strong resistances that are challenging for breakouts and may require strong catalysts; OR (b) " . $wrap_symb . " may have had adept reverse traders in that session; OR (c) " . $wrap_symb . " may not have had sufficient upside actions in that session; OR (d) " . $wrap_symb . " might have had a low-risk and low-return or negative session.", ); /** *@var is a list of keywords for article */ $tags = $symb . " Stock, " . $symb . " Intraday Trading, " . $symb . " Investing, " . $symb . " Option Pricing, " . $symb . " Day Trading, " . $symb . " Swing Trading, " . $symb . " Put and Call Forecast, " . $symb . " Price Target, " . $symb . " Premarket, " . $comp . ", " . $sect . ", " . $mark; /** *@var is title 1 for article */ $page_title = $symb . " " . $comp . " Trading and Investing Equilibrium Price Analytics: " . money_format('%=4.2n', ST::getMean($array["m"]["p"])) . " | " . $dt; /** *@var is title 2 for article */ $article_title = $symb . " - " . $comp . " Actual vs. Approximated Equity Prices - " . sizeof($array["chart"]) . " Sessions: " . $fd . " - " . $ld; /** *@var is an array of meta parameters for MD files */ $meta = array( "user_id" => null, "page_id" => $page_id, "page_title" => $page_title, "page_about" => $page_about, "page_description" => $page_description, "page_tags" => $tags, "page_publish_date" => $dt, "page_update_date" => $dt, "page_image" => ConstEQ::LOGO_LARGE, "page_template" => "templates/equilibrium-estimation", "page_robots" => "index,follow", "article_display" => "1", "article_title" => $article_title, "article_publish_date" => $dt, "article_update_date" => $dt, "article_author" => "Equity Team", "article_image" => null, "article_chart" => null, "article_tags" => $tags, ); /** *@var is the entire HTML for the entire Article */ $all_html = ''; /** *@var is meta content in the beginning of MD file */ foreach ($meta as $k => $v) { $all_html .= $k . ": " . $v . ConstEQ::NEW_LINE; } /** *@var is just some empty lines required after meta in the MD file */ $all_html = "---" . ConstEQ::NEW_LINE . $all_html . "---" . ConstEQ::NEW_LINE . ConstEQ::NEW_LINE; // mandatory separator in the md file /** *@var is start of HTML */ $all_html .= '<section itemscope itemtype="http://schema.org/AnalysisNewsArticle" class="ro mv-3">'; $all_html .= '<div class="img-2 pr-no b1' . rand(20, 99) . '" style="background-image:url(' . ConstEQ::PROTOCOL . ConstEQ::DOMAIN . ConstEQ::SLASH . ConstEQ::LOGO_LARGE . ');padding:19% 0 0 0;"><img itemprop="image" src="' . ConstEQ::PROTOCOL . ConstEQ::DOMAIN . ConstEQ::SLASH . ConstEQ::LOGO_LARGE . '" class="di-0" alt=""/>'; // logo $all_html .= '<div class="ro p-5 tx-0 pr-no">'; $all_html .= '<h1 itemprop="headline" class="s16 fw-6 r100 b1' . rand(20, 99) . ' p-3 br-5 o9">'; $all_html .= $article_highlight; // article highlight box on the top of the page $all_html .= '</h1>'; $all_html .= '</div>'; $all_html .= '</div>'; $all_html .= ConstEQ::NEW_LINE; // required spacer for view $all_html .= '<h2 itemprop="name" class="tx-1 fw-8">'; $all_html .= $article_title; // article title $all_html .= '</h2>'; $all_html .= ConstEQ::NEW_LINE; // required spacer for view if ($array["m"]["g"]) { $all_html .= '<p class="ro p-5 fw-6 tx-1 s16 r113">Near-Term Price Targets Computed on ' . date('l, d F Y \⏱ H:i T', microtime(true)) . '</p>'; $all_html .= ConstEQ::NEW_LINE; // required spacer for view $all_html .= '<ul class="ro p-5 fw-6 tx-1 s18 r113">'; /** *@var is a counter from 1 to 7 */ $c = 0; foreach ($array["m"]["g"] as $k => $v) { $c++; $r = rand(20, 99); $all_html .= '<li>'; $all_html .= '<b class="di-1 t-21 m-1 br-3 p-2 b119 r1' . $r . '"> ' . $c . '</b>:'; $all_html .= '<b class="di-1 t-21 m-1 br-3 p-2 b119 r1' . $r . '"> ' . $v . '</b>'; $all_html .= '</li>'; } $all_html .= '</ul>'; $all_html .= ConstEQ::NEW_LINE; // required spacer for view } /** *@method is for getting equilibrium prices HTML */ $all_html .= self::getEquilibriumHTML($array); $all_html .= ConstEQ::NEW_LINE; // required spacer for view /** *@method is for getting the latest quote HTML */ $all_html .= self::getQuoteHTML($array["quote"]); $all_html .= ConstEQ::NEW_LINE; // required spacer for view /** *@var adds the abstract of article */ $all_html .= '<p itemprop="about" class="ro p-5 fw-6 tx-3 s12 r113">'; $all_html .= $article_abstract; // article short summary $all_html .= '</p>'; $all_html .= ConstEQ::NEW_LINE; // required spacer for view /** *@var is for adding indicator description */ $all_html .= '<ul itemprop="description" class="ro p-5 fw-6 tx-3 s12 r113">'; foreach ($indicators as $k => $v) { $r = rand(20, 99); $all_html .= '<li>'; $all_html .= '<b class="di-1 t-21 m-1 br-3 p-2 b119 r1' . $r . '">' . $k . '</b>'; $all_html .= '<b>: ' . $v . '</b>'; $all_html .= '</li>'; } $all_html .= '</ul>'; $all_html .= ConstEQ::NEW_LINE; // required spacer for view $all_html .= '</section>'; $all_html .= ConstEQ::NEW_LINE; // required spacer for view $all_html .= '<b class="ro tx-1 s35 mv-5">'; $all_html .= EQ::getSectorEmojis(7, $sect, $class_obj->emojis); // 7 random emojis $all_html .= '</b>'; $all_html .= ConstEQ::NEW_LINE; // required spacer for view /** *@var is JSON/LD schema.org for structured data for google */ $all_html .= '<script type="application/ld+json">{'; $all_html .= '"@context": "http://schema.org",'; $all_html .= '"@type": "Article",'; $all_html .= '"headline": "' . $article_title . '",'; $all_html .= '"alternativeHeadline": "' . $page_title . '",'; $all_html .= '"dateCreated": "' . ConstEQ::DATE_CREATED . '",'; $all_html .= '"datePublished": "' . ConstEQ::DATE_CREATED . '",'; $all_html .= '"dateModified": "' . $dt . '",'; $all_html .= '"description": "' . $article_abstract . '",'; $all_html .= '"keywords": "' . $tags . '",'; $all_html .= '"publisher": {"@type":"organization","logo":{"type" :"ImageObject","url":"' . ConstEQ::PROTOCOL . ConstEQ::DOMAIN . ConstEQ::SLASH . ConstEQ::LOGO_SMALL . '"},"name":"' . ConstEQ::ORGANIZATION . '"},'; $all_html .= '"author": {"@type":"organization","name":"' . ConstEQ::ARTICLE_TEAM . '"},'; $all_html .= '"mainEntityOfPage": "' . $url . '",'; $all_html .= '"image": ["' . ConstEQ::PROTOCOL . ConstEQ::DOMAIN . ConstEQ::SLASH . ConstEQ::LOGO_LARGE . '"],'; $all_html .= '"url": "' . $url . '"'; $all_html .= '}</script>'; $all_html .= ConstEQ::NEW_LINE; // required spacer for view /** *@var is the final entire HTML to embed in the MD file after meta */ return $all_html; } /** * [ ['Mon', 20, 28, 38, 45], ['Tue', 31, 38, 55, 66], ['Wed', 50, 55, 77, 80], ['Thu', 77, 77, 66, 50], ['Fri', 68, 66, 22, 15] ] * @return an HTML string for a chart using google chart API */ public static function getCandlestickChart($arr) { $html = '<div id="chart_div" class="ro"></div>'; $html .= '<script type="text/javascript" src="https://www.gstatic.com/charts/loader.js"></script>'; $html .= '<script type="text/javascript">'; $html .= "google.charts.load('current', {'packages':['corechart']});"; $html .= "google.charts.setOnLoadCallback(drawChart);"; $html .= "function drawChart() { var data = google.visualization.arrayToDataTable(" . $arr . ", true); var options = { title:'Candlestick Chart: Low Support, VWAP, Equilibrium, High Resistance', legend:'none', selectionMode:'multiple', agregationTarget:'category', height:data.getNumberOfRows()*25, orientation:'vertical', theme:{ axisTitlePosition:'in', hAxis:{titlePosition:'in'}, }, tooltip:{ trigger:'selection', textStyle:{ color:'#3A5FCD', showColorCode:true, fontSize:12, bold:true, isHTML:true } }, chartArea: { left:'1%', top:50, right:0, bottom:75, backgroundColor:'#333', }, hAxis:{ title:'Equity Prices', titleTextStyle:{ color:'#63B8FF', fontSize:20, bold:true }, textStyle:{ color:'#014B96', fontSize:15, bold:true }, format:'currency' }, vAxis:{ textStyle:{ color:'#8968CD', fontSize:10, bold:true }, minorGridlines:{ color:'#EEEE00', count:10, } }, candlestick:{ risingColor:{stroke:'#EEEE00',fill:'#32CD32'}, fallingColor:{stroke:'#858585',fill:'#FF4500'} }, colors:['#4169E1'] }; var chart = new google.visualization.CandlestickChart(document.getElementById('chart_div')); chart.draw(data, options); } </script>"; return $html; } /** * * @return a large HTML string of past 20 sessions equilibrium estimations with 7 volatilities */ public static function getMobileEquilibrium($arr) { $html = ''; // child html $eq_htmls = ''; // parent html if (is_array(array_column($arr, "m")[0])) { $ps = array_column($arr, "m")[0]; } else { $ps = array(); } foreach ($ps as $k => $p) { for ($i = (sizeof($p) / 4) - 1; $i >= 0; $i--) { $r = rand(0, 9); if ($i === (sizeof($p) / 4) - 1) { $html .= '<div class="ro di-2 a120 a220 a320 a420 a520 a620 a720 sq-1 br-5 mv-5 b11' . $r . ' r100 sq-1">'; $html .= '<div class="ro tx-1 s16">' . $arr["c"]["c"][$k]["s"] . '</div>'; // session date $html .= '<div class="ro a120 a220 a320 a420 a520 a620 a720">'; $html .= '<b id="a-0" class="s18 a118 a218 a318 a418 a518 a618 a718 r18' . $r . ' mv-2 tx-0 di-1"> Actual Low</b>'; $html .= '<b id="a-1" class="s18 a118 a218 a318 a418 a518 a618 a718 r10' . $r . ' mv-2 tx-1 di-1"> Actual VWAP</b>'; $html .= '<b id="a-2" class="s18 a118 a218 a318 a418 a518 a618 a718 r14' . $r . ' mv-2 tx-2 di-1"> Actual High</b>'; $html .= '</div>'; $html .= '<div class="ro a120 a220 a320 a420 a520 a620 a720">'; $html .= '<b id="b-0' . $i . '" class="s18 a118 a218 a318 a418 a518 a618 a718 r18' . $r . ' mv-2 tx-0 di-1">' . $arr["c"]["c"][$k]["l"] . '</b>'; $html .= '<b id="b-1' . $i . '" class="s18 a118 a218 a318 a418 a518 a618 a718 r10' . $r . ' mv-2 tx-1 di-1">' . $arr["c"]["c"][$k]["w"] . '</b>'; $html .= '<b id="b-2' . $i . '" class="s18 a118 a218 a318 a418 a518 a618 a718 r14' . $r . ' mv-2 tx-2 di-1">' . $arr["c"]["c"][$k]["h"] . '</b>'; $html .= '</div>'; $html .= '<div class="ro a120 a220 a320 a420 a520 a620 a720">'; $html .= '<b id="e-0" class="s15 a118 a218 a318 a418 a518 a618 a718 r18' . $r . ' mv-2 tx-0 di-1"> Approximated Supports</b>'; $html .= '<b id="e-1" class="s15 a118 a218 a318 a418 a518 a618 a718 r10' . $r . ' mv-2 tx-1 di-1"> Estimated Equilibriums </b>'; $html .= '<b id="e-2" class="s15 a118 a218 a318 a418 a518 a618 a718 r14' . $r . ' mv-2 tx-2 di-1"> Approximated Resistances</b>'; $html .= '</div>'; $html .= '<div class="ro a120 a220 a320 a420 a520 a620 a720">'; $html .= '<b id="b-0' . $i . '" class="s16 a118 a218 a318 a418 a518 a618 a718 r18' . $r . ' mv-1 tx-0 di-1"> ' . $p["l" . $i] . ' </b>'; $html .= '<b id="b-1' . $i . '" class="s16 a118 a218 a318 a418 a518 a618 a718 r10' . $r . ' mv-1 tx-1 di-1"> ' . $p["e" . $i] . ' </b>'; $html .= '<b id="b-2' . $i . '" class="s16 a118 a218 a318 a418 a518 a618 a718 r14' . $r . ' mv-1 tx-2 di-1"> ' . $p["h" . $i] . ' </b>'; $html .= '</div>'; $html .= '<div class="ro a120 a220 a320 a420 a520 a620 a720 g-3 fh-2 cu-cm"></div>'; $html .= '<div style="padding-left:' . round(44 + $p["p" . $i]) . '%;" class="ro di-1"><div class="tg-up t-19">' . round(50 + $p["p" . $i], 3) . '%</div></div>'; } elseif ($i > 0 && $i < sizeof($p) / 4 - 1) { $html .= '<div class="ro a120 a220 a320 a420 a520 a620 a720">'; $html .= '<b id="b-0' . $i . '" class="s16 a118 a218 a318 a418 a518 a618 a718 r18' . $r . ' mv-1 tx-0 di-1"> ' . $p["l" . $i] . ' </b>'; $html .= '<b id="b-1' . $i . '" class="s16 a118 a218 a318 a418 a518 a618 a718 r10' . $r . ' mv-1 tx-1 di-1"> ' . $p["e" . $i] . ' </b>'; $html .= '<b id="b-2' . $i . '" class="s16 a118 a218 a318 a418 a518 a618 a718 r14' . $r . ' mv-1 tx-2 di-1"> ' . $p["h" . $i] . ' </b>'; $html .= '</div>'; $html .= '<div class="ro a120 a220 a320 a420 a520 a620 a720 g-3 fh-2 cu-cm"></div>'; $html .= '<div style="padding-left:' . round(44 + $p["p" . $i]) . '%;" class="ro di-1"><div class="tg-up t-19">' . round(50 + $p["p" . $i], 3) . '%</div></div>'; } elseif ($i === 0) { $html .= '<div class="ro a120 a220 a320 a420 a520 a620 a720">'; $html .= '<b id="b-0' . $i . '" class="s16 a118 a218 a318 a418 a518 a618 a718 r18' . $r . ' mv-1 tx-0 di-1"> ' . $p["l" . $i] . ' </b>'; $html .= '<b id="b-1' . $i . '" class="s16 a118 a218 a318 a418 a518 a618 a718 r10' . $r . ' mv-1 tx-1 di-1"> ' . $p["e" . $i] . ' </b>'; $html .= '<b id="b-2' . $i . '" class="s16 a118 a218 a318 a418 a518 a618 a718 r14' . $r . ' mv-1 tx-2 di-1"> ' . $p["h" . $i] . ' </b>'; $html .= '</div>'; $html .= '<div class="ro a120 a220 a320 a420 a520 a620 a720 g-3 fh-2 cu-cm"></div>'; $html .= '<div style="padding-left:' . round(44 + $p["p" . $i]) . '%;" class="ro di-1"><div class="tg-up t-19">' . round(50 + $p["p" . $i], 3) . '%</div></div>'; $html .= '<div class="ro a120 a220 a320 a420 a520 a620 a720">'; $html .= '<b id="b-0' . $i . '" class="s16 a118 a218 a318 a418 a518 a618 a718 r18' . $r . ' mv-2 tx-0 di-1"> Lowest Lows</b>'; $html .= '<b id="b-1' . $i . '" class="s16 a118 a218 a318 a418 a518 a618 a718 r10' . $r . ' mv-2 tx-1 di-1"> Equilibriums </b>'; $html .= '<b id="b-2' . $i . '" class="s16 a118 a218 a318 a418 a518 a618 a718 r14' . $r . ' mv-2 tx-2 di-1"> Highest Highs</b>'; $html .= '</div>'; $html .= '</div>'; } else { if ($_SERVER['LOGNAME'] === ConstEQ::LOCALHOST) { HelperEQ::linePrint("OOPS! It might be sizeof($p)/4, Check the algorithm! πŸ’” " . ConstEQ::NEW_LINE); } continue; } $eq_htmls .= $html; $html = ''; } } /** *@var is a button for open/close equilibrium data */ $click_button = '<a href="#" class="s18 ro tx-1 b119 r100 t-21 p-2 br-5 mv-3" onclick="J.toggleSwitch({d:this});return false;" title="' . $arr["quote"]["symbol"] . ' latest quote">πŸŽ› Average Daily Equilibrium Forecast: ' . date('l, d F Y \⏱ H:i T', microtime(true)) . '</a>'; return '<div class="ro">' . $click_button . '<div class="di-0"><div class="p-3">' . $eq_htmls . '</div></div></div>'; } /** * * @return a large HTML string of current quote section */ public static function getQuoteHTML($a) { /** *@method gets majority of quote array parameters */ $quote_params = ST::getQuoteParams(); /** *@var is the HTML for quote section of the article */ $html = '<div class="ro">' . '<a href="#"' . ' class="s18 ro tx-1 b119 r100 t-21 p-2 br-5 mv-3"' . ' onclick="J.toggleSwitch({d:this}); return false;"' . ' title="' . $a["symbol"] . ' latest quote">' . ' πŸ’Ή Quote: ' . date('l, d F Y \⏱ H:i T', microtime(true)) . '</a>' . '<div class="di-0">' . '<div class="p-3">'; foreach ($quote_params as $param) { if (!isset($param["id"]) || empty($a[$param["ky"]])) { continue; } $rand = rand(20, 99); $html .= '<p id="' . $param["id"] . '">'; $html .= '<b class="di-1 t-21 m-1 br-3 p-2 b119 r1' . $rand . '">' . $param["lb"] . '</b>: '; $html .= '<b class="di-1 t-21 m-1 br-3 p-2 b119 r1' . $rand . '">'; switch ($param["id"][0]) { case "s": $html .= $a[$param["ky"]]; break; case "d": case "v": $html .= money_format('%=9.4n', (double) $a[$param["ky"]]); break; case "t": $html .= date('l, d F Y \⏱ H:i T \(P \U\T\C\)', (double) $a[$param["ky"]] / 1000); break; case "p": $html .= money_format('%=9.4n', (double) $a[$param["ky"]]) . '%'; break; default: $html .= $a[$param["ky"]] . '%'; } $html .= '</b>'; $html .= '</p>'; } $html .= '</div>' . '</div>' . '</div>'; return $html; } /** * * @return an HTML string for a chart using google chart API */ public static function getEquilibriumHTML($arr) { if (is_array(array_column($arr, "m")[0])) { $ps = array_column($arr, "m")[0]; } else { $ps = array(); } $candle_chart_arr = array(); foreach ($ps as $k => $p) { for ($i = (sizeof($p) / 4) - 1; $i >= 0; $i--) { array_push($candle_chart_arr, array( $arr["c"]["c"][$k]["s"], // date (float) substr($p["l" . $i], 1), // low support estimated (float) substr($arr["c"]["c"][$k]["w"], 1), // VWAP market price (float) substr($p["e" . $i], 1), // Equilibrium estimated (float) substr($p["h" . $i], 1), // high resistance estimated ) ); } } return HTMLviewEQ::getCandlestickChart(json_encode($candle_chart_arr, true)); } } 
\$\endgroup\$

    2 Answers 2

    4
    \$\begingroup\$

    I wanted to write a comment, but it got a bit too long, so I made it into an answer.

    First of all: This question is lacking context. What is it used for, what does it do, how is it used? You could have explained this in your question. However, I did follow your link and found out that this is a tiny part of an app that: "... scrapes equity data from iextrading API, does statistical analytics, and returns daily price target articles for ~8000 equities in NYSE, NASDAQ and CBOE markets in HTML forms.". Oh! Not my area of expertise.

    I can't run your code, so I can't say whether the code achieves its final purpose, but I will assume it does. I will restrict myself to looking at your code and make some comments.

    Your class file starts with:

    date_default_timezone_set("America/New_York"); ini_set('max_execution_time', 0); ini_set('memory_limit', '-1'); set_time_limit(0); require_once __DIR__ . "/HTMLviewEQ.php"; 

    I don't understand what this is doing here? Clearly this is not a file that is meant to be run as a stand alone entity. Why then, is this here? I see you do this in all your class files. In case you want to change the default time zone, you'll have to change it everywhere. Does that make sense? Why not put this in 1 central location in your app?

    Whenever I look at new code I try to understand the intent behind it. In the case of a single PHP class, the first real line is always a good start. It is:

    class HTMLviewEQ extends EQ implements ConstEQ 

    Now I get that EQ means Equity, that's what the whole program is about. Given the HTMLview part, I think this class must have something to do with HTML output. However the class names EQ and ConstEQ don't give much away.

    Let me see what methods there are:

    public static function getBaseHTML($array, $page_id, $class_obj) public static function getCandlestickChart($arr) public static function getMobileEquilibrium($arr) public static function getQuoteHTML($a) public static function getEquilibriumHTML($arr) 

    Well, they all 'get' something, that's obvious. I have no idea what 'BaseHTML' could be? The only thing I really understand is the 'CandlestickChart'. That must return a chart, and although it doesn't say, that must be in HTML.

    Since it looks like all method output HTML, I wonder why this class is called HTMLviewEQ. It doesn't produce a 'view' by itself. It is probably only used to construct one?

    Argument names like $array, $arr or $a, don't really tell me what they represent. Worse, I don't even know if they contain the same content, or not. I don't think so, otherwise you would have used the same name. These names are basically meaningless. The same is true for $class_obj. The only meaningful argument is $page_id, if only I knew what pages you're talking about.

    Names are very important in any programming language. They allow you to tell the reader what they represent and, with that, what your code does. Good names are: customerName, CurrencySymbol and ClockTicks. Bad names are: myConst, bksp, symb and strObj.

    One of my personal hangups are unnecessary abbreviations. Why should I have to guess what a name stands for? When I encounter: $dt, $comp, $fd and $ld in your code I have to look up what they mean. Why? What's wrong with $currentDate, $companyName, $firstChartDate and $lastChartDate? Slightly longer names won't make any difference to the speed with which the code is executed, but they make a big difference to the reader.

    At this point this class, and its methods, don't make any sense to me. They're not 'talking'. For all I know you could have just thrown a few overly big functions together to make this class. I can't see any design or structure to it.

    I will have to accept that I can't understand the code, and look at what is going on in each method.

    getBaseHTML() is BIG. Line wrap on! Basically it's way too big. This is not good programming. This method doesn't do one thing, it does lots of things. This is not a good way to produce HTML. Code and text are completely mixed up in one big code-slurry. It's inflexible, and difficult to understand.

    Now I don't want to say: You have to use a templating package, but this is the opposite. PHP code, text and HTML are all mixed together here. Oh, there's some Javascript too. It doesn't make sense and is very difficult to maintain.

    To start I would separate the text from the HTML, and probably put it in a database or a separate file. Earmark them. Something like:

    $articleText = ['highlight' => "{companyName}: Seven price sets are being approximated for {wrappedSymbol} lowest supports, {wrappedSymbol} average equilibriums and {wrappedSymbol} highest resistances. Each set has a \"percentage\", which indicates that if {wrappedSymbol} has been outperforming or downperforming during that day.", 'abstract' => "{wrappedSymbol} - {companyName}: Equilibrium price is important for {wrappedSymbol} institutional trading/investing, {wrappedSymbol} retail trading/investing and other types of short/long positions. They provide supplementary perspectives to traders for {wrappedSymbol} day/swing trading, {wrappedSymbol} low/high frequency trading, {wrappedSymbol} put/call option forecasting, {wrappedSymbol} forward/reverse trading/investing and {wrappedSymbol} algorithmic trading. Average equilibrium price is necessary for {wrappedSymbol} Buy/Sell/Hold decision makings and {wrappedSymbol} rating for analyst coverages and equity due diligence. They are also beneficial for {wrappedSymbol} trading volume forecasting, {wrappedSymbol} daily volatility approximating, {wrappedSymbol} resistance and support evaluating, {wrappedSymbol} stop loss calculations, among other quantitative advantages. Static charts cannot provide such information to trading and investing entities.", 'legalWarning' => "All {symbol} information are connected to delayed 60-seconds data pipelines from version 1.0 API at https://api.iextrading.com/1.0/, in addition to other financial and economical data. All computations are automatic, currently independent of all news, sentiments, external parameters and internal corporate factors. This page is only an alpha prototype and is only updated a few times per hour based on our dynamic indices and latest quote scraped from that API. It may not be accessible at all times, and inadvertent or unknown inaccuracies exist. All information are provided under \"AT YOUR OWN FULL RISKS\" and \"NO LIABILITIES, UNDER NO CIRCUMSTANCES\" terms. Trade Safe and Happy Investing!"]; 

    And then use these strings to create your HTML output. In the end proper templating is most flexible, but something like this will do for now. You can easily edit these string, and you could even write an UI for that. HTML can be used to structure content, whereas the text should conveys meaning. These are two different things.

    There's lots of other things to say about your code, but let me stop here. I'll summarize:

    • Class files should only contain a class, nothing else.
    • PHP names should be meaningful: $quoteAmount instead of $a.
    • Methods should not be overly long and do one thing.
    • Separate HTML from texts. Don't mix everything up.

    OOP is more than just a bit of syntax, it's a method. A way to structure your thoughts and code. You're clearly not yet thinking in object and classes. To you they must seem more like a hindrance than a tool.

    I always found PHP The Right Way a good starting point to learn more. You can find everything there, from a Code Style Guide, Coding Practices, to Templates and Security. A lot of essential resources at your fingertips!

    And when you're tired of it all, you could have a look at PHP The Wrong Way. To counterbalance it all a bit.

    \$\endgroup\$
    0
      2
      \$\begingroup\$

      You have a lot of characters being loaded into $html string. Try to find repeated string sequences and try to cache them in a fashion that allow you to quickly reference and potentially loop the data.

      Using DRY techniques, will make your code more concise, easier to maintain, less susceptible to typos, and generally makes proper use of a language that offers variables.

      For instance, have a look at the repetition of:

      $html .= '<b id="b-0' . $i . '" class="s16 a118 a218 a318 a418 a518 a618 a718 r18' . $r . ' mv-1 tx-0 di-1"> ' . $p["l" . $i] . ' </b>'; $html .= '<b id="b-1' . $i . '" class="s16 a118 a218 a318 a418 a518 a618 a718 r10' . $r . ' mv-1 tx-1 di-1"> ' . $p["e" . $i] . ' </b>'; $html .= '<b id="b-2' . $i . '" class="s16 a118 a218 a318 a418 a518 a618 a718 r14' . $r . ' mv-1 tx-2 di-1"> ' . $p["h" . $i] . ' </b>'; 

      The class values could very sensibly be stored as a lookup array like this:

      $classLookup = [ 's16 a118 a218 a318 a418 a518 a618 a718 r18', 's16 a118 a218 a318 a418 a518 a618 a718 r10', 's16 a118 a218 a318 a418 a518 a618 a718 r14' ]; 

      Then you could write short loops to cut down on the hardcoded parts of your script. Something like:

      foreach($classLookup as $x => $classes) { $html .= '<b id="b-' . $x . $i . '" class="' . $classes . $r . ' mv-1 tx-{$x} di-1"> ' . $p["l" . $i] . ' </b>'; } 

      You might not take this advice literally. Have a think about what is going to be the way to set up the variables and try not to repeat yourself.

      When writing your foreach() loops, if you don't use the key variable, then don't bother declaring it.

      I see a few places inside of loops where you ask php to repeatedly calculate (sizeof($p) / 4) - 1. While it is not a very taxing calculation, good coding practices dictate that you should calculate and declare this value as a variable, once, outside your loop. Then simply reference it when needed.

      Cast your eyes to the design of your if-elseif-else block. Find any similarities/duplications and try to redesign your script to reduce much of the hardcoded strings.

      \$\endgroup\$
      0

        Start asking to get answers

        Find the answer to your question by asking.

        Ask question

        Explore related questions

        See similar questions with these tags.