Merge pull request #438 from danielyxie/stock-market-update

Stock market update
This commit is contained in:
danielyxie 2018-08-25 17:08:09 -05:00 committed by GitHub
commit c8158e1d19
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 353 additions and 88 deletions

@ -552,6 +552,17 @@
#stock-market-container { #stock-market-container {
position: fixed; position: fixed;
padding: 6px; padding: 6px;
p {
font-size: $defaultFontSize * 0.8125;
}
a {
font-size: $defaultFontSize * 0.875;
}
h2 {
margin-top:10px;
margin-left:10px;
display:block;
}
} }
#stock-market-container p { #stock-market-container p {
@ -564,6 +575,11 @@
margin: 10px; margin: 10px;
} }
#stock-market-watchlist-filter {
width:50%;
margin-left:10px;
}
.stock-market-input { .stock-market-input {
display: inline-block; display: inline-block;
padding: 4px; padding: 4px;

@ -310,11 +310,23 @@ a:visited {
display: inline-block; display: inline-block;
} }
.help-tip:hover { .help-tip-big {
content: '?';
padding: 3px;
margin-left: 3px;
color: #fff;
border: 1px solid #fff;
border-radius: 8px;
display: inline-block;
}
.help-tip:hover,
.help-tip-big:hover {
background-color: #888; background-color: #888;
} }
.help-tip:active { .help-tip:active,
.help-tip-big:active {
@include boxShadow(inset 0 1px 4px rgba(0, 0, 0, 0.6)); @include boxShadow(inset 0 1px 4px rgba(0, 0, 0, 0.6));
} }

@ -143,7 +143,9 @@ getActionEstimatedSuccessChance
:param string type: Type of action. See :ref:`bladeburner_action_types` :param string type: Type of action. See :ref:`bladeburner_action_types`
:param string name: Name of action. Must be an exact match :param string name: Name of action. Must be an exact match
Returns the estimated success chance for the specified action Returns the estimated success chance for the specified action. This chance
is returned as a decimal value, NOT a percentage (e.g. if you have an estimated
success chance of 80%, then this function will return 0.80, NOT 80).
getActionCountRemaining getActionCountRemaining
----------------------- -----------------------

@ -172,3 +172,38 @@ cancelOrder
Cancels an oustanding Limit or Stop order on the stock market. Cancels an oustanding Limit or Stop order on the stock market.
The ability to use limit and stop orders is **not** immediately available to the player and must be unlocked later on in the game. The ability to use limit and stop orders is **not** immediately available to the player and must be unlocked later on in the game.
getStockVolatility
------------------
.. js:function:: getStockVolatility(sym)
:param string sym: Symbol of stock
Returns the volatility of the specified stock.
Volatility represents the maximum percentage by which a stock's price can
change every tick. The volatility is returned as a decimal value, NOT
a percentage (e.g. if a stock has a volatility of 3%, then this function will
return 0.03, NOT 3).
In order to use this function, you must first purchase access to the Four Sigma (4S)
Market Data TIX API.
getStockForecast
----------------
.. js:function:: getStockForecast(sym)
:param string sym: Symbol of stock
Returns the probability that the specified stock's price will increase
(as opposed to decrease) during the next tick.
The probability is returned as a decimal value, NOT a percentage (e.g. if a
stock has a 60% chance of increasing, then this function will return 0.6,
NOT 60).
In other words, if this function returned 0.30 for a stock, then this means
that the stock's price has a 30% chance of increasing and a 70% chance of
decreasing during the next tick.

@ -679,22 +679,44 @@
after you 'reset' by installing Augmentations. after you 'reset' by installing Augmentations.
</p> </p>
<a id="stock-market-buy-account" class="a-link-button-inactive"> Buy WSE Account </a> <a id="stock-market-buy-account" class="a-link-button-inactive"> Buy WSE Account </a>
<a id="stock-market-investopedia" class="a-link-button">Investopedia</a>
<h2> Trade Information eXchange (TIX) API </h2>
<p> <p>
You can also purchase access to the World Stock Exchange's TIX API! TIX, short for TIX, short for Trade Information eXchange, is the communications protocol supported by the WSE.
Trade Information eXchange, is the communications protocol supported by the WSE. Purchasing access to the TIX API lets you write code to create your own algorithmic/automated
<br><br> trading strategies.
Gaining access to the TIX API lets you write code to build automated trading
systems. In other words, you can create your own algorithmic trading strategies!
<br><br> <br><br>
If you purchase access to the TIX API, you will retain that access even after If you purchase access to the TIX API, you will retain that access even after
you 'reset' by installing Augmentations. you 'reset' by installing Augmentations.
</p> </p>
<a id="stock-market-buy-tix-api" class="a-link-button-inactive">Buy Trade Information eXchange (TIX) API Access</a> <a id="stock-market-buy-tix-api" class="a-link-button-inactive">Buy Trade Information eXchange (TIX) API Access</a>
<a id="stock-market-investopedia" class="a-link-button">Investopedia</a>
<h2> Four Sigma (4S) Market Data Feed </h2>
<p>
Four Sigma's (4S) Market Data Feed provides information about stocks
that will help your trading strategies.
<br><br>
If you purchase access to 4S Market Data and/or the 4S TIX API, you will
retain that access even after you 'reset' by installing Augmentations.
</p>
<a id="stock-market-buy-4s-data" class="a-link-button-inactive tooltip">
Buy 4S Market Data Feed
</a>
<div class="help-tip-big" id="stock-market-4s-data-help-tip">?</div>
<a id="stock-market-buy-4s-tix-api" class="a-link-button-inactive tooltip">
Buy 4S Market Data TIX API Access
</a>
<p id="stock-market-commission"> </p> <p id="stock-market-commission"> </p>
<a id="stock-market-mode" class="a-link-button tooltip"></a> <a id="stock-market-mode" class="a-link-button tooltip"></a>
<a id="stock-market-expand-tickers" class="a-link-button tooltip">Expand tickers</a> <a id="stock-market-expand-tickers" class="a-link-button tooltip">Expand tickers</a>
<a id="stock-market-collapse-tickers" class="a-link-button tooltip">Collapse tickers</a> <a id="stock-market-collapse-tickers" class="a-link-button tooltip">Collapse tickers</a>
<br><br>
<input id="stock-market-watchlist-filter" type="text" placeholder="Filter Stocks by symbol (comma-separated list)"> </input>
<a id="stock-market-watchlist-filter-update" class="a-link-button"> Update Watchlist </a>
<ul id="stock-market-list" style="list-style:none;"> <ul id="stock-market-list" style="list-style:none;">
</ul> </ul>
</div> </div>

@ -101,5 +101,5 @@
"watch": "webpack --watch --mode production", "watch": "webpack --watch --mode production",
"watch:dev": "webpack --watch --mode development" "watch:dev": "webpack --watch --mode development"
}, },
"version": "0.35.1" "version": "0.40.2"
} }

@ -115,6 +115,8 @@ let CONSTANTS = {
//Stock market constants //Stock market constants
WSEAccountCost: 200e6, WSEAccountCost: 200e6,
TIXAPICost: 5e9, TIXAPICost: 5e9,
MarketData4SCost: 1e9,
MarketDataTixApi4SCost: 20e9,
StockMarketCommission: 100e3, StockMarketCommission: 100e3,
//Hospital/Health //Hospital/Health
@ -492,9 +494,9 @@ let CONSTANTS = {
LatestUpdate: LatestUpdate:
"v0.40.2<br>" + "v0.40.2<br>" +
"------------------------------<br>" +
"* Bladeburner Changes:<br>" + "* Bladeburner Changes:<br>" +
"*** Added getSkillUpgradeCost() Netscript function to the API<br>" + "*** Added getBonusTime(), getSkillUpgradeCost(), and getCity() Netscript functions to the API<br>" +
"*** Added getBonusTime() Netscript function to the API<br>" +
"*** Buffed the effects of many Bladeburner Augmentations<br>" + "*** Buffed the effects of many Bladeburner Augmentations<br>" +
"*** The Blade's Simulacrum Augmentation requires significantly less reputation but slightly more money<br>" + "*** The Blade's Simulacrum Augmentation requires significantly less reputation but slightly more money<br>" +
"*** Slightly increased the amount of successes needed for a Contract/Operation in order to increase its max level<br>" + "*** Slightly increased the amount of successes needed for a Contract/Operation in order to increase its max level<br>" +
@ -504,6 +506,12 @@ let CONSTANTS = {
"*** The number (count) of Operations should now increase significantly faster<br>" + "*** The number (count) of Operations should now increase significantly faster<br>" +
"*** There are now, on average, more Synthoid communities in a city<br>" + "*** There are now, on average, more Synthoid communities in a city<br>" +
"*** If automation is enabled (the feature in Bladeburner console), then switching to another action such as working for a company will now disable the automation<br>" + "*** If automation is enabled (the feature in Bladeburner console), then switching to another action such as working for a company will now disable the automation<br>" +
"------------------------------<br>" +
"* Stock Market Changes:<br>" +
"***Added a watchlist filter feature to the UI that allows you to specify which stocks to show<br>" +
"***Added the Four Sigma (4S) Market Data feed, which provides volatility and price forecast information about stocks<br>" +
"***Added the 4S Market Data TIX API, which lets you access the aforementioned data through Netscript<br>" +
"------------------------------<br>" +
"* There is now a setting for enabling/disabling the popup that appears when you are hospitalized<br>" + "* There is now a setting for enabling/disabling the popup that appears when you are hospitalized<br>" +
"* Bug Fix: Stock market should now be correctly initialized in BitNode-8 (by Kline-)<br>" + "* Bug Fix: Stock market should now be correctly initialized in BitNode-8 (by Kline-)<br>" +
"* Bug Fix: bladeburner.getCurrentAction() should now properly an 'Idle' object rather than null (by Kline-)<br>" + "* Bug Fix: bladeburner.getCurrentAction() should now properly an 'Idle' object rather than null (by Kline-)<br>" +

@ -1599,6 +1599,36 @@ function NetscriptFunctions(workerScript) {
}; };
return cancelOrder(params, workerScript); return cancelOrder(params, workerScript);
}, },
getStockVolatility : function(symbol) {
if (workerScript.checkingRam) {
return updateStaticRam("getStockVolatility", CONSTANTS.ScriptBuySellStockRamCost);
}
updateDynamicRam("getStockVolatility", CONSTANTS.ScriptBuySellStockRamCost);
if (!Player.has4SDataTixApi) {
throw makeRuntimeRejectMsg(workerScript, "You don't have 4S Market Data TIX API Access! Cannot use getStockVolatility()");
}
var stock = SymbolToStockMap[symbol];
if (stock == null) {
throw makeRuntimeRejectMsg(workerScript, "ERROR: Invalid stock symbol passed into getStockVolatility()");
}
return stock.mv / 100; //Convert from percentage to decimal
},
getStockForecast : function(symbol) {
if (workerScript.checkingRam) {
return updateStaticRam("getStockForecast", CONSTANTS.ScriptBuySellStockRamCost);
}
updateDynamicRam("getStockForecast", CONSTANTS.ScriptBuySellStockRamCost);
if (!Player.has4SDataTixApi) {
throw makeRuntimeRejectMsg(workerScript, "You don't have 4S Market Data TIX API Access! Cannot use getStockForecast()");
}
var stock = SymbolToStockMap[symbol];
if (stock == null) {
throw makeRuntimeRejectMsg(workerScript, "ERROR: Invalid stock symbol passed into getStockForecast()");
}
var forecast = 50;
stock.b ? forecast += stock.otlkMag : forecast -= stock.otlkMag;
return forecast / 100; //Convert from percentage to decimal
},
getPurchasedServerLimit : function() { getPurchasedServerLimit : function() {
if (workerScript.checkingRam) { if (workerScript.checkingRam) {
return updateStaticRam("getPurchasedServerLimit", CONSTANTS.ScriptGetPurchasedServerLimit); return updateStaticRam("getPurchasedServerLimit", CONSTANTS.ScriptGetPurchasedServerLimit);
@ -3744,6 +3774,21 @@ function NetscriptFunctions(workerScript) {
throw makeRuntimeRejectMsg(workerScript, "getCityChaos() failed because you do not currently have access to the Bladeburner API. This is either because you are not currently employed " + throw makeRuntimeRejectMsg(workerScript, "getCityChaos() failed because you do not currently have access to the Bladeburner API. This is either because you are not currently employed " +
"at the Bladeburner division or because you do not have Source-File 7"); "at the Bladeburner division or because you do not have Source-File 7");
}, },
getCity : function() {
if (workerScript.checkingRam) {
return updateStaticRam("getCity", CONSTANTS.ScriptBladeburnerApiBaseRamCost);
}
updateDynamicRam("getCity", CONSTANTS.ScriptBladeburnerApiBaseRamCost);
if (Player.bladeburner instanceof Bladeburner && (Player.bitNodeN === 7 || hasBladeburner2079SF)) {
try {
return Player.bladeburner.city;
} catch(e) {
throw makeRuntimeRejectMsg(workerScript, "Bladeburner.getCity() failed with exception: " + e);
}
}
throw makeRuntimeRejectMsg(workerScript, "getCity() failed because you do not currently have access to the Bladeburner API. This is either because you are not currently employed " +
"at the Bladeburner division or because you do not have Source-File 7");
},
switchCity : function(cityName) { switchCity : function(cityName) {
if (workerScript.checkingRam) { if (workerScript.checkingRam) {
return updateStaticRam("switchCity", CONSTANTS.ScriptBladeburnerApiBaseRamCost); return updateStaticRam("switchCity", CONSTANTS.ScriptBladeburnerApiBaseRamCost);

@ -173,6 +173,8 @@ function PlayerObject() {
//Stock Market //Stock Market
this.hasWseAccount = false; this.hasWseAccount = false;
this.hasTixApiAccess = false; this.hasTixApiAccess = false;
this.has4SData = false;
this.has4SDataTixApi = false;
//Gang //Gang
this.gang = 0; this.gang = 0;

@ -10,7 +10,11 @@ import {Reviver, Generic_toJSON,
Generic_fromJSON} from "../utils/JSONReviver"; Generic_fromJSON} from "../utils/JSONReviver";
import {Page, routing} from "./ui/navigationTracking"; import {Page, routing} from "./ui/navigationTracking";
import numeral from "numeral/min/numeral.min"; import numeral from "numeral/min/numeral.min";
import {exceptionAlert} from "../utils/helpers/exceptionAlert";
import {getRandomInt} from "../utils/helpers/getRandomInt"; import {getRandomInt} from "../utils/helpers/getRandomInt";
import {KEY} from "../utils/helpers/keyCodes";
import {createElement} from "../utils/uiHelpers/createElement";
import {removeChildrenFromElement} from "../utils/uiHelpers/removeChildrenFromElement";
import {removeElementById} from "../utils/uiHelpers/removeElementById"; import {removeElementById} from "../utils/uiHelpers/removeElementById";
import {yesNoBoxCreate, yesNoTxtInpBoxCreate, import {yesNoBoxCreate, yesNoTxtInpBoxCreate,
yesNoBoxGetYesButton, yesNoBoxGetNoButton, yesNoBoxGetYesButton, yesNoBoxGetNoButton,
@ -409,6 +413,7 @@ function stockMarketCycle() {
for (var name in StockMarket) { for (var name in StockMarket) {
if (StockMarket.hasOwnProperty(name)) { if (StockMarket.hasOwnProperty(name)) {
var stock = StockMarket[name]; var stock = StockMarket[name];
if (!(stock instanceof Stock)) {continue;}
var thresh = 0.6; var thresh = 0.6;
if (stock.b) {thresh = 0.4;} if (stock.b) {thresh = 0.4;}
if (Math.random() < thresh) { if (Math.random() < thresh) {
@ -695,18 +700,29 @@ var COMM = CONSTANTS.StockMarketCommission;
function displayStockMarketContent() { function displayStockMarketContent() {
if (Player.hasWseAccount == null) {Player.hasWseAccount = false;} if (Player.hasWseAccount == null) {Player.hasWseAccount = false;}
if (Player.hasTixApiAccess == null) {Player.hasTixApiAccess = false;} if (Player.hasTixApiAccess == null) {Player.hasTixApiAccess = false;}
if (Player.has4SData == null) {Player.has4SData = false;}
if (Player.has4SDataTixApi == null) {Player.has4SDataTixApi = false;}
function stylePurchaseButton(btn, cost, flag, initMsg, purchasedMsg) {
btn.innerText = initMsg;
btn.classList.remove("a-link-button");
btn.classList.remove("a-link-button-bought");
btn.classList.remove("a-link-button-inactive");
if (!flag && Player.money.gte(cost)) {
btn.classList.add("a-link-button");
} else if (flag) {
btn.innerText = purchasedMsg;
btn.classList.add("a-link-button-bought");
} else {
btn.classList.add("a-link-button-inactive");
}
}
//Purchase WSE Account button //Purchase WSE Account button
var wseAccountButton = clearEventListeners("stock-market-buy-account"); var wseAccountButton = clearEventListeners("stock-market-buy-account");
wseAccountButton.innerText = "Buy WSE Account - " + numeral(CONSTANTS.WSEAccountCost).format('($0.000a)'); stylePurchaseButton(wseAccountButton, CONSTANTS.WSEAccountCost, Player.hasWseAccount,
if (!Player.hasWseAccount && Player.money.gte(CONSTANTS.WSEAccountCost)) { "Buy WSE Account - " + numeral(CONSTANTS.WSEAccountCost).format('($0.000a)'),
wseAccountButton.setAttribute("class", "a-link-button"); "WSE Account - Purchased");
} else if (Player.hasWseAccount){
wseAccountButton.innerText = "WSE Account - Purchased";
wseAccountButton.setAttribute("class", "a-link-button-bought");
} else {
wseAccountButton.setAttribute("class", "a-link-button-inactive");
}
wseAccountButton.addEventListener("click", function() { wseAccountButton.addEventListener("click", function() {
Player.hasWseAccount = true; Player.hasWseAccount = true;
initStockMarket(); initStockMarket();
@ -718,16 +734,9 @@ function displayStockMarketContent() {
//Purchase TIX API Access account //Purchase TIX API Access account
var tixApiAccessButton = clearEventListeners("stock-market-buy-tix-api"); var tixApiAccessButton = clearEventListeners("stock-market-buy-tix-api");
tixApiAccessButton.innerText = "Buy Trade Information eXchange (TIX) API Access - " + stylePurchaseButton(tixApiAccessButton, CONSTANTS.TIXAPICost, Player.hasTixApiAccess,
numeral(CONSTANTS.TIXAPICost).format('($0.000a)'); "Buy Trade Information eXchange (TIX) API Access - " + numeral(CONSTANTS.TIXAPICost).format('($0.000a)'),
if (!Player.hasTixApiAccess && Player.money.gte(CONSTANTS.TIXAPICost)) { "TIX API Access - Purchased");
tixApiAccessButton.setAttribute("class", "a-link-button");
} else if(Player.hasTixApiAccess) {
tixApiAccessButton.innerText = "Trade Information eXchange (TIX) API Access - Purchased"
tixApiAccessButton.setAttribute("class", "a-link-button-bought");
} else {
tixApiAccessButton.setAttribute("class", "a-link-button-inactive");
}
tixApiAccessButton.addEventListener("click", function() { tixApiAccessButton.addEventListener("click", function() {
Player.hasTixApiAccess = true; Player.hasTixApiAccess = true;
Player.loseMoney(CONSTANTS.TIXAPICost); Player.loseMoney(CONSTANTS.TIXAPICost);
@ -735,9 +744,76 @@ function displayStockMarketContent() {
return false; return false;
}); });
//Purchase Four Sigma Market Data Feed
var marketDataButton = clearEventListeners("stock-market-buy-4s-data");
stylePurchaseButton(marketDataButton, CONSTANTS.MarketData4SCost, Player.has4SData,
"Buy 4S Market Data Access - " + numeral(CONSTANTS.MarketData4SCost).format('($0.000a)'),
"4S Market Data - Purchased");
marketDataButton.addEventListener("click", function() {
Player.has4SData = true;
Player.loseMoney(CONSTANTS.MarketData4SCost);
displayStockMarketContent();
return false;
});
marketDataButton.appendChild(createElement("span", {
class:"tooltiptext",
innerText:"Lets you view additional pricing and volatility information about stocks"
}));
marketDataButton.style.marginRight = "2px"; //Adjusts following help tip to be slightly closer
//4S Market Data Help Tip
var marketDataHelpTip = clearEventListeners("stock-market-4s-data-help-tip");
marketDataHelpTip.style.marginTop = "10px";
marketDataHelpTip.addEventListener("click", ()=>{
dialogBoxCreate("Access to the 4S Market Data feed will display two additional pieces " +
"of information about each stock: Price Forecast & Volatility<br><br>" +
"Price Forecast indicates the probability the stock has of increasing or " +
"decreasing. A '+' forecast means the stock has a higher chance of increasing " +
"than decreasing, and a '-' means the opposite. The number of '+/-' symbols " +
"is used to illustrate the magnitude of these probabilities. For example, " +
"'+++' means that the stock has a significantly higher chance of increasing " +
"than decreasing, while '+' means that the stock only has a slightly higher chance " +
"of increasing than decreasing.<br><br>" +
"Volatility represents the maximum percentage by which a stock's price " +
"can change every tick (a tick occurs every few seconds while the game " +
"is running).<br><br>" +
"A stock's price forecast can change over time. This is also affected by volatility. " +
"The more volatile a stock is, the more its price forecast will change.");
return false;
});
//Purchase Four Sigma Market Data TIX API (Requires TIX API Access)
var marketDataTixButton = clearEventListeners("stock-market-buy-4s-tix-api");
stylePurchaseButton(marketDataTixButton, CONSTANTS.MarketDataTixApi4SCost, Player.has4SDataTixApi,
"Buy 4S Market Data TIX API Access - " + numeral(CONSTANTS.MarketDataTixApi4SCost).format('($0.000a)'),
"4S Market Data TIX API - Purchased");
if (Player.hasTixApiAccess) {
marketDataTixButton.addEventListener("click", function() {
Player.has4SDataTixApi = true;
Player.loseMoney(CONSTANTS.MarketDataTixApi4SCost);
displayStockMarketContent();
return false;
});
marketDataTixButton.appendChild(createElement("span", {
class:"tooltiptext",
innerText:"Lets you access 4S Market Data through Netscript"
}));
} else {
marketDataTixButton.classList.remove("a-link-button");
marketDataTixButton.classList.remove("a-link-button-bought");
marketDataTixButton.classList.remove("a-link-button-inactive");
marketDataTixButton.classList.add("a-link-button-inactive");
marketDataTixButton.appendChild(createElement("span", {
class:"tooltiptext",
innerText:"Requires TIX API Access"
}));
}
var stockList = document.getElementById("stock-market-list"); var stockList = document.getElementById("stock-market-list");
if (stockList == null) {return;} if (stockList == null) {return;}
//If Player doesn't have account, clear stocks UI and return
if (!Player.hasWseAccount) { if (!Player.hasWseAccount) {
stockMarketContentCreated = false; stockMarketContentCreated = false;
while (stockList.firstChild) { while (stockList.firstChild) {
@ -834,14 +910,32 @@ function displayStockMarketContent() {
}); });
} }
for (var name in StockMarket) { //Watchlish filter
if (StockMarket.hasOwnProperty(name)) { var watchlistFilter = clearEventListeners("stock-market-watchlist-filter");
var stock = StockMarket[name]; var watchlistUpdateBtn = clearEventListeners("stock-market-watchlist-filter-update");
if (!(stock instanceof Stock)) {continue;} //orders property is an array if (watchlistFilter && watchlistUpdateBtn) {
createStockTicker(stock); //Initialize value in watchlist
if (StockMarket.watchlistFilter) {
watchlistFilter.value = StockMarket.watchlistFilter; //Remove whitespace
} }
watchlistUpdateBtn.addEventListener("click", ()=> {
let filterValue = watchlistFilter.value.toString();
StockMarket.watchlistFilter = filterValue.replace(/\s/g, '');
if (stockMarketPortfolioMode) {
switchToPortfolioMode();
} else {
switchToDisplayAllMode();
} }
setStockTickerClickHandlers(); //Clicking headers opens/closes panels });
watchlistFilter.addEventListener("keyup", (e)=>{
e.preventDefault();
if (e.keyCode === KEY.ENTER) {watchlistUpdateBtn.click();}
})
} else {
console.warn("Stock Market Watchlist DOM elements could not be found");
}
createAllStockTickers();
stockMarketContentCreated = true; stockMarketContentCreated = true;
} }
@ -849,27 +943,46 @@ function displayStockMarketContent() {
for (var name in StockMarket) { for (var name in StockMarket) {
if (StockMarket.hasOwnProperty(name)) { if (StockMarket.hasOwnProperty(name)) {
var stock = StockMarket[name]; var stock = StockMarket[name];
if (stock instanceof Stock) {
updateStockTicker(stock, null); updateStockTicker(stock, null);
updateStockOrderList(stock); updateStockOrderList(stock);
} }
} }
} }
}
} }
//Displays only stocks you have position/order in //Displays only stocks you have position/order in
function switchToPortfolioMode() { function switchToPortfolioMode() {
stockMarketPortfolioMode = true; stockMarketPortfolioMode = true;
var stockList = document.getElementById("stock-market-list");
if (stockList == null) {return;}
var modeBtn = clearEventListeners("stock-market-mode"); var modeBtn = clearEventListeners("stock-market-mode");
if (modeBtn) { if (modeBtn) {
modeBtn.innerHTML = "Switch to 'All stocks' Mode" + modeBtn.innerHTML = "Switch to 'All stocks' Mode" +
"<span class='tooltiptext'>Displays all stocks on the WSE</span>"; "<span class='tooltiptext'>Displays all stocks on the WSE</span>";
modeBtn.addEventListener("click", switchToDisplayAllMode); modeBtn.addEventListener("click", switchToDisplayAllMode);
} }
while(stockList.firstChild) {stockList.removeChild(stockList.firstChild);} createAllStockTickers();
}
//Displays all stocks
function switchToDisplayAllMode() {
stockMarketPortfolioMode = false;
var modeBtn = clearEventListeners("stock-market-mode");
if (modeBtn) {
modeBtn.innerHTML = "Switch to 'Portfolio' Mode" +
"<span class='tooltiptext'>Displays only the stocks for which you have shares or orders</span>";
modeBtn.addEventListener("click", switchToPortfolioMode);
}
createAllStockTickers();
}
function createAllStockTickers() {
var stockList = document.getElementById("stock-market-list");
if (stockList == null) {
exceptionAlert("Error creating Stock Tickers UI. DOM element with ID 'stock-market-list' could not be found");
}
removeChildrenFromElement(stockList);
//Get Order book (create it if it hasn't been created)
var orderBook = StockMarket["Orders"]; var orderBook = StockMarket["Orders"];
if (orderBook == null) { if (orderBook == null) {
var orders = {}; var orders = {};
@ -881,41 +994,30 @@ function switchToPortfolioMode() {
} }
} }
StockMarket["Orders"] = orders; StockMarket["Orders"] = orders;
orderBook = StockMarket["Orders"];
}
let watchlist = null;
if (StockMarket.watchlistFilter != null && StockMarket.watchlistFilter !== "") {
let filter = StockMarket.watchlistFilter.replace(/\s/g, '');
watchlist = filter.split(",");
} }
for (var name in StockMarket) { for (var name in StockMarket) {
if (StockMarket.hasOwnProperty(name)) { if (StockMarket.hasOwnProperty(name)) {
var stock = StockMarket[name]; var stock = StockMarket[name];
if (!(stock instanceof Stock)) {continue;} //orders property is an array if (!(stock instanceof Stock)) {continue;} //orders property is an array
var stockOrders = orderBook[stock.symbol]; if (watchlist && !watchlist.includes(stock.symbol)) {continue;} //Watchlist filtering
let stockOrders = orderBook[stock.symbol];
if (stockMarketPortfolioMode) {
if (stock.playerShares === 0 && stock.playerShortShares === 0 && if (stock.playerShares === 0 && stock.playerShortShares === 0 &&
stockOrders.length === 0) {continue;} stockOrders.length === 0) {continue;}
}
createStockTicker(stock); createStockTicker(stock);
} }
} }
setStockTickerClickHandlers(); setStockTickerClickHandlers(); //Clicking headers opens/closes panels
}
//Displays all stocks
function switchToDisplayAllMode() {
stockMarketPortfolioMode = false;
var stockList = document.getElementById("stock-market-list");
if (stockList == null) {return;}
var modeBtn = clearEventListeners("stock-market-mode");
if (modeBtn) {
modeBtn.innerHTML = "Switch to 'Portfolio' Mode" +
"<span class='tooltiptext'>Displays only the stocks for which you have shares or orders</span>";
modeBtn.addEventListener("click", switchToPortfolioMode);
}
while(stockList.firstChild) {stockList.removeChild(stockList.firstChild);}
for (var name in StockMarket) {
if (StockMarket.hasOwnProperty(name)) {
var stock = StockMarket[name];
if (!(stock instanceof Stock)) {continue;} //orders property is an array
createStockTicker(stock);
}
}
setStockTickerClickHandlers();
} }
function createStockTicker(stock) { function createStockTicker(stock) {
@ -1196,10 +1298,25 @@ function updateStockTicker(stock, increase) {
var hdr = document.getElementById(tickerId + "-hdr"); var hdr = document.getElementById(tickerId + "-hdr");
if (hdr == null) { if (hdr == null) {
if (!stockMarketPortfolioMode) {console.log("ERROR: Couldn't find ticker element for stock: " + stock.symbol);} if (!stockMarketPortfolioMode) {
let watchlist = StockMarket.watchlistFilter;
if (watchlist !== "" && watchlist.includes(stock.symbol)) {
console.log("ERROR: Couldn't find ticker element for stock: " + stock.symbol);
}
}
return; return;
} }
hdr.innerHTML = stock.name + " - " + stock.symbol + " - " + numeral(stock.price).format('($0.000a)'); let hdrText = stock.name + " (" + stock.symbol + ") - " + numeral(stock.price).format('($0.000a)');
if (Player.has4SData) {
hdrText += " - Volatility: " + numeral(stock.mv).format('0,0.00') + "%" +
" - Price Forecast: ";
if (stock.b) {
hdrText += "+".repeat(Math.floor(stock.otlkMag/10) + 1);
} else {
hdrText += "-".repeat(Math.floor(stock.otlkMag/10) + 1);
}
}
hdr.innerText = hdrText;
if (increase != null) { if (increase != null) {
increase ? hdr.style.color = "#66ff33" : hdr.style.color = "red"; increase ? hdr.style.color = "#66ff33" : hdr.style.color = "red";
} }
@ -1280,7 +1397,13 @@ function updateStockOrderList(stock) {
var tickerId = "stock-market-ticker-" + stock.symbol; var tickerId = "stock-market-ticker-" + stock.symbol;
var orderList = document.getElementById(tickerId + "-order-list"); var orderList = document.getElementById(tickerId + "-order-list");
if (orderList == null) { if (orderList == null) {
if (!stockMarketPortfolioMode) {console.log("ERROR: Could not find order list for " + stock.symbol);} //Log only if its a valid error
if (!stockMarketPortfolioMode) {
let watchlist = StockMarket.watchlistFilter;
if (watchlist !== "" && watchlist.includes(stock.symbol)) {
console.log("ERROR: Could not find order list for " + stock.symbol);
}
}
return; return;
} }