Added Four Sigma (4S) Market Data feature, and its Netscript TIX API functions as well

This commit is contained in:
Daniel Xie 2018-08-24 15:44:48 -05:00
parent 815762bddd
commit e4f02b298b
9 changed files with 261 additions and 47 deletions

@ -552,6 +552,17 @@
#stock-market-container {
position: fixed;
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 {

@ -310,11 +310,23 @@ a:visited {
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;
}
.help-tip:active {
.help-tip:active,
.help-tip-big:active {
@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 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
-----------------------

@ -172,3 +172,38 @@ cancelOrder
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.
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,18 +679,37 @@
after you 'reset' by installing Augmentations.
</p>
<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>
You can also purchase access to the World Stock Exchange's TIX API! TIX, short for
Trade Information eXchange, is the communications protocol supported by the WSE.
<br><br>
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!
TIX, short for 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
trading strategies.
<br><br>
If you purchase access to the TIX API, you will retain that access even after
you 'reset' by installing Augmentations.
</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-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>
<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>

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

@ -115,6 +115,8 @@ let CONSTANTS = {
//Stock market constants
WSEAccountCost: 200e6,
TIXAPICost: 5e9,
MarketData4SCost: 1e9,
MarketDataTixApi4SCost: 20e9,
StockMarketCommission: 100e3,
//Hospital/Health
@ -492,9 +494,9 @@ let CONSTANTS = {
LatestUpdate:
"v0.40.2<br>" +
"------------------------------<br>" +
"* Bladeburner Changes:<br>" +
"*** Added getSkillUpgradeCost() Netscript function to the API<br>" +
"*** Added getBonusTime() Netscript function to the API<br>" +
"*** Added getBonusTime(), getSkillUpgradeCost(), and getCity() Netscript functions to the API<br>" +
"*** Buffed the effects of many Bladeburner Augmentations<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>" +
@ -504,6 +506,12 @@ let CONSTANTS = {
"*** The number (count) of Operations should now increase significantly faster<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>" +
"------------------------------<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>" +
"* 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>" +

@ -1599,6 +1599,36 @@ function NetscriptFunctions(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() {
if (workerScript.checkingRam) {
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 " +
"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) {
if (workerScript.checkingRam) {
return updateStaticRam("switchCity", CONSTANTS.ScriptBladeburnerApiBaseRamCost);

@ -13,6 +13,7 @@ import numeral from "numeral/min/numeral.min";
import {exceptionAlert} from "../utils/helpers/exceptionAlert";
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 {yesNoBoxCreate, yesNoTxtInpBoxCreate,
@ -699,18 +700,29 @@ var COMM = CONSTANTS.StockMarketCommission;
function displayStockMarketContent() {
if (Player.hasWseAccount == null) {Player.hasWseAccount = 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
var wseAccountButton = clearEventListeners("stock-market-buy-account");
wseAccountButton.innerText = "Buy WSE Account - " + numeral(CONSTANTS.WSEAccountCost).format('($0.000a)');
if (!Player.hasWseAccount && Player.money.gte(CONSTANTS.WSEAccountCost)) {
wseAccountButton.setAttribute("class", "a-link-button");
} else if (Player.hasWseAccount){
wseAccountButton.innerText = "WSE Account - Purchased";
wseAccountButton.setAttribute("class", "a-link-button-bought");
} else {
wseAccountButton.setAttribute("class", "a-link-button-inactive");
}
stylePurchaseButton(wseAccountButton, CONSTANTS.WSEAccountCost, Player.hasWseAccount,
"Buy WSE Account - " + numeral(CONSTANTS.WSEAccountCost).format('($0.000a)'),
"WSE Account - Purchased");
wseAccountButton.addEventListener("click", function() {
Player.hasWseAccount = true;
initStockMarket();
@ -722,16 +734,9 @@ function displayStockMarketContent() {
//Purchase TIX API Access account
var tixApiAccessButton = clearEventListeners("stock-market-buy-tix-api");
tixApiAccessButton.innerText = "Buy Trade Information eXchange (TIX) API Access - " +
numeral(CONSTANTS.TIXAPICost).format('($0.000a)');
if (!Player.hasTixApiAccess && Player.money.gte(CONSTANTS.TIXAPICost)) {
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");
}
stylePurchaseButton(tixApiAccessButton, CONSTANTS.TIXAPICost, Player.hasTixApiAccess,
"Buy Trade Information eXchange (TIX) API Access - " + numeral(CONSTANTS.TIXAPICost).format('($0.000a)'),
"TIX API Access - Purchased");
tixApiAccessButton.addEventListener("click", function() {
Player.hasTixApiAccess = true;
Player.loseMoney(CONSTANTS.TIXAPICost);
@ -739,9 +744,76 @@ function displayStockMarketContent() {
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");
if (stockList == null) {return;}
//If Player doesn't have account, clear stocks UI and return
if (!Player.hasWseAccount) {
stockMarketContentCreated = false;
while (stockList.firstChild) {
@ -1234,7 +1306,17 @@ function updateStockTicker(stock, increase) {
}
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) {
increase ? hdr.style.color = "#66ff33" : hdr.style.color = "red";
}