import {CONSTANTS} from "./Constants.js";
import {Engine} from "./engine.js";
import {Locations} from "./Location.js";
import {hasWallStreetSF, wallStreetSFLvl} from "./NetscriptFunctions.js";
import {WorkerScript} from "./NetscriptWorker.js";
import {Player} from "./Player.js";
import {dialogBoxCreate} from "../utils/DialogBox.js";
import {clearEventListeners, getRandomInt,
removeElementById,
clearEventListenersEl} from "../utils/HelperFunctions.js";
import {Reviver, Generic_toJSON,
Generic_fromJSON} from "../utils/JSONReviver.js";
import numeral from "../utils/numeral.min.js";
import {formatNumber} from "../utils/StringHelperFunctions.js";
import {yesNoBoxCreate, yesNoTxtInpBoxCreate,
yesNoBoxGetYesButton, yesNoBoxGetNoButton,
yesNoTxtInpBoxGetYesButton, yesNoTxtInpBoxGetNoButton,
yesNoTxtInpBoxGetInput, yesNoBoxClose,
yesNoTxtInpBoxClose, yesNoBoxOpen} from "../utils/YesNoBox.js";
/* StockMarket.js */
function Stock(name, symbol, mv, b, otlkMag, initPrice=10000) {
this.symbol = symbol;
this.name = name;
this.price = initPrice;
this.playerShares = 0;
this.playerAvgPx = 0;
this.playerShortShares = 0;
this.playerAvgShortPx = 0;
this.mv = mv;
this.b = b;
this.otlkMag = otlkMag;
this.posTxtEl = null;
}
Stock.prototype.toJSON = function() {
return Generic_toJSON("Stock", this);
}
Stock.fromJSON = function(value) {
return Generic_fromJSON(Stock, value.data);
}
Reviver.constructors.Stock = Stock;
var OrderTypes = {
LimitBuy: "Limit Buy Order",
LimitSell: "Limit Sell Order",
StopBuy: "Stop Buy Order",
StopSell: "Stop Sell Order"
}
var PositionTypes = {
Long: "L",
Short: "S"
}
function placeOrder(stock, shares, price, type, position, workerScript=null) {
var tixApi = (workerScript instanceof WorkerScript);
var order = new Order(stock, shares, price, type, position);
if (isNaN(shares) || isNaN(price)) {
if (tixApi) {
workerScript.scriptRef.log("ERROR: Invalid numeric value provided for either 'shares' or 'price' argument");
} else {
dialogBoxCreate("ERROR: Invalid numeric value provided for either 'shares' or 'price' argument");
}
return false;
}
if (StockMarket["Orders"] == null) {
var orders = {};
for (var name in StockMarket) {
if (StockMarket.hasOwnProperty(name)) {
var stock = StockMarket[name];
if (!(stock instanceof Stock)) {continue;}
orders[stock.symbol] = [];
}
}
StockMarket["Orders"] = orders;
}
StockMarket["Orders"][stock.symbol].push(order);
//Process to see if it should be executed immediately
processOrders(order.stock, order.type, order.pos);
updateStockOrderList(order.stock);
return true;
}
//Returns true if successfully cancels an order, false otherwise
function cancelOrder(params, workerScript=null) {
var tixApi = (workerScript instanceof WorkerScript);
if (StockMarket["Orders"] == null) {return false;}
if (params.order && params.order instanceof Order) {
var order = params.order;
//An 'Order' object is passed in
var stockOrders = StockMarket["Orders"][order.stock.symbol];
for (var i = 0; i < stockOrders.length; ++i) {
if (order == stockOrders[i]) {
stockOrders.splice(i, 1);
updateStockOrderList(order.stock);
return true;
}
}
return false;
} else if (params.stock && params.shares && params.price && params.type &&
params.pos && params.stock instanceof Stock) {
//Order properties are passed in. Need to look for the order
var stockOrders = StockMarket["Orders"][params.stock.symbol];
var orderTxt = params.stock.symbol + " - " + params.shares + " @ " +
numeral(params.price).format('$0.000a');
for (var i = 0; i < stockOrders.length; ++i) {
var order = stockOrders[i];
if (params.shares === order.shares &&
params.price === order.price &&
params.type === order.type &&
params.pos === order.pos) {
stockOrders.splice(i, 1);
updateStockOrderList(order.stock);
if (tixApi) {
workerScript.scriptRef.log("Successfully cancelled order: " + orderTxt);
}
return true;
}
}
if (tixApi) {
workerScript.scriptRef.log("Failed to cancel order: " + orderTxt);
}
return false;
}
return false;
}
function executeOrder(order) {
var stock = order.stock;
var orderBook = StockMarket["Orders"];
var stockOrders = orderBook[stock.symbol];
var res = true;
console.log("Executing the following order:");
console.log(order);
switch (order.type) {
case OrderTypes.LimitBuy:
case OrderTypes.StopBuy:
if (order.pos === PositionTypes.Long) {
res = buyStock(order.stock, order.shares) && res;
} else if (order.pos === PositionTypes.Short) {
res = shortStock(order.stock, order.shares) && res;
}
break;
case OrderTypes.LimitSell:
case OrderTypes.StopSell:
if (order.pos === PositionTypes.Long) {
res = sellStock(order.stock, order.shares) && res;
} else if (order.pos === PositionTypes.Short) {
res = sellShort(order.stock, order.shares) && res;
}
break;
}
if (res) {
//Remove order from order book
for (var i = 0; i < stockOrders.length; ++i) {
if (order == stockOrders[i]) {
stockOrders.splice(i, 1);
updateStockOrderList(order.stock);
return;
}
}
console.log("ERROR: Could not find the following Order in Order Book: ");
console.log(order);
} else {
console.log("Order failed to execute");
}
}
function Order(stock, shares, price, type, position) {
this.stock = stock;
this.shares = shares;
this.price = price;
this.type = type;
this.pos = position;
}
Order.prototype.toJSON = function() {
return Generic_toJSON("Order", this);
}
Order.fromJSON = function(value) {
return Generic_fromJSON(Order, value.data);
}
Reviver.constructors.Order = Order;
let StockMarket = {} //Full name to stock object
let StockSymbols = {} //Full name to symbol
let SymbolToStockMap = {}; //Symbol to Stock object
function loadStockMarket(saveString) {
if (saveString === "") {
StockMarket = {};
} else {
StockMarket = JSON.parse(saveString, Reviver);
}
}
function initStockSymbols() {
//Stocks for companies at which you can work
StockSymbols[Locations.AevumECorp] = "ECP";
StockSymbols[Locations.Sector12MegaCorp] = "MGCP";
StockSymbols[Locations.Sector12BladeIndustries] = "BLD";
StockSymbols[Locations.AevumClarkeIncorporated] = "CLRK";
StockSymbols[Locations.VolhavenOmniTekIncorporated] = "OMTK";
StockSymbols[Locations.Sector12FourSigma] = "FSIG";
StockSymbols[Locations.ChongqingKuaiGongInternational] = "KGI";
StockSymbols[Locations.AevumFulcrumTechnologies] = "FLCM";
StockSymbols[Locations.IshimaStormTechnologies] = "STM";
StockSymbols[Locations.NewTokyoDefComm] = "DCOMM";
StockSymbols[Locations.VolhavenHeliosLabs] = "HLS";
StockSymbols[Locations.NewTokyoVitaLife] = "VITA";
StockSymbols[Locations.Sector12IcarusMicrosystems] = "ICRS";
StockSymbols[Locations.Sector12UniversalEnergy] = "UNV";
StockSymbols[Locations.AevumAeroCorp] = "AERO";
StockSymbols[Locations.VolhavenOmniaCybersystems] = "OMN";
StockSymbols[Locations.ChongqingSolarisSpaceSystems] = "SLRS";
StockSymbols[Locations.NewTokyoGlobalPharmaceuticals] = "GPH";
StockSymbols[Locations.IshimaNovaMedical] = "NVMD";
StockSymbols[Locations.AevumWatchdogSecurity] = "WDS";
StockSymbols[Locations.VolhavenLexoCorp] = "LXO";
StockSymbols[Locations.AevumRhoConstruction] = "RHOC";
StockSymbols[Locations.Sector12AlphaEnterprises] = "APHE";
StockSymbols[Locations.VolhavenSysCoreSecurities] = "SYSC";
StockSymbols[Locations.VolhavenCompuTek] = "CTK";
StockSymbols[Locations.AevumNetLinkTechnologies] = "NTLK";
StockSymbols[Locations.IshimaOmegaSoftware] = "OMGA";
StockSymbols[Locations.Sector12FoodNStuff] = "FNS";
//Stocks for other companies
StockSymbols["Sigma Cosmetics"] = "SGC";
StockSymbols["Joes Guns"] = "JGN";
StockSymbols["Catalyst Ventures"] = "CTYS";
StockSymbols["Microdyne Technologies"] = "MDYN";
StockSymbols["Titan Laboratories"] = "TITN";
}
function initStockMarket() {
for (var stk in StockMarket) {
if (StockMarket.hasOwnProperty(stk)) {
delete StockMarket[stk];
}
}
var ecorp = Locations.AevumECorp;
var ecorpStk = new Stock(ecorp, StockSymbols[ecorp], 0.45, true, 19, getRandomInt(20000, 25000));
StockMarket[ecorp] = ecorpStk;
var megacorp = Locations.Sector12MegaCorp;
var megacorpStk = new Stock(megacorp, StockSymbols[megacorp], 0.45, true, 19, getRandomInt(25000, 33000));
StockMarket[megacorp] = megacorpStk;
var blade = Locations.Sector12BladeIndustries;
var bladeStk = new Stock(blade, StockSymbols[blade], 0.75, true, 13, getRandomInt(15000, 22000));
StockMarket[blade] = bladeStk;
var clarke = Locations.AevumClarkeIncorporated;
var clarkeStk = new Stock(clarke, StockSymbols[clarke], 0.7, true, 12, getRandomInt(15000, 20000));
StockMarket[clarke] = clarkeStk;
var omnitek = Locations.VolhavenOmniTekIncorporated;
var omnitekStk = new Stock(omnitek, StockSymbols[omnitek], 0.65, true, 12, getRandomInt(35000, 40000));
StockMarket[omnitek] = omnitekStk;
var foursigma = Locations.Sector12FourSigma;
var foursigmaStk = new Stock(foursigma, StockSymbols[foursigma], 1.05, true, 17, getRandomInt(60000, 70000));
StockMarket[foursigma] = foursigmaStk;
var kuaigong = Locations.ChongqingKuaiGongInternational;
var kuaigongStk = new Stock(kuaigong, StockSymbols[kuaigong], 0.8, true, 10, getRandomInt(20000, 24000));
StockMarket[kuaigong] = kuaigongStk;
var fulcrum = Locations.AevumFulcrumTechnologies;
var fulcrumStk = new Stock(fulcrum, StockSymbols[fulcrum], 1.25, true, 16, getRandomInt(30000, 35000));
StockMarket[fulcrum] = fulcrumStk;
var storm = Locations.IshimaStormTechnologies;
var stormStk = new Stock(storm, StockSymbols[storm], 0.85, true, 7, getRandomInt(21000, 24000));
StockMarket[storm] = stormStk;
var defcomm = Locations.NewTokyoDefComm;
var defcommStk = new Stock(defcomm, StockSymbols[defcomm], 0.65, true, 10, getRandomInt(10000, 15000));
StockMarket[defcomm] = defcommStk;
var helios = Locations.VolhavenHeliosLabs;
var heliosStk = new Stock(helios, StockSymbols[helios], 0.6, true, 9, getRandomInt(12000, 16000));
StockMarket[helios] = heliosStk;
var vitalife = Locations.NewTokyoVitaLife;
var vitalifeStk = new Stock(vitalife, StockSymbols[vitalife], 0.75, true, 7, getRandomInt(10000, 12000));
StockMarket[vitalife] = vitalifeStk;
var icarus = Locations.Sector12IcarusMicrosystems;
var icarusStk = new Stock(icarus, StockSymbols[icarus], 0.65, true, 7.5, getRandomInt(16000, 20000));
StockMarket[icarus] = icarusStk;
var universalenergy = Locations.Sector12UniversalEnergy;
var universalenergyStk = new Stock(universalenergy, StockSymbols[universalenergy], 0.55, true, 10, getRandomInt(20000, 25000));
StockMarket[universalenergy] = universalenergyStk;
var aerocorp = Locations.AevumAeroCorp;
var aerocorpStk = new Stock(aerocorp, StockSymbols[aerocorp], 0.6, true, 6, getRandomInt(10000, 15000));
StockMarket[aerocorp] = aerocorpStk;
var omnia = Locations.VolhavenOmniaCybersystems;
var omniaStk = new Stock(omnia, StockSymbols[omnia], 0.7, true, 4.5, getRandomInt(9000, 12000));
StockMarket[omnia] = omniaStk;
var solaris = Locations.ChongqingSolarisSpaceSystems;
var solarisStk = new Stock(solaris, StockSymbols[solaris], 0.75, true, 8.5, getRandomInt(18000, 24000));
StockMarket[solaris] = solarisStk;
var globalpharm = Locations.NewTokyoGlobalPharmaceuticals;
var globalpharmStk = new Stock(globalpharm, StockSymbols[globalpharm], 0.6, true, 10.5, getRandomInt(18000, 24000));
StockMarket[globalpharm] = globalpharmStk;
var nova = Locations.IshimaNovaMedical;
var novaStk = new Stock(nova, StockSymbols[nova], 0.75, true, 5, getRandomInt(18000, 24000));
StockMarket[nova] = novaStk;
var watchdog = Locations.AevumWatchdogSecurity;
var watchdogStk = new Stock(watchdog, StockSymbols[watchdog], 2.5, true, 1.5, getRandomInt(5000, 7500));
StockMarket[watchdog] = watchdogStk;
var lexocorp = Locations.VolhavenLexoCorp;
var lexocorpStk = new Stock(lexocorp, StockSymbols[lexocorp], 1.25, true, 6, getRandomInt(5000, 7500));
StockMarket[lexocorp] = lexocorpStk;
var rho = Locations.AevumRhoConstruction;
var rhoStk = new Stock(rho, StockSymbols[rho], 0.6, true, 1, getRandomInt(3000, 6000));
StockMarket[rho] = rhoStk;
var alpha = Locations.Sector12AlphaEnterprises;
var alphaStk = new Stock(alpha, StockSymbols[alpha], 1.9, true, 10, getRandomInt(5000, 7500));
StockMarket[alpha] = alphaStk;
var syscore = Locations.VolhavenSysCoreSecurities;
var syscoreStk = new Stock(syscore, StockSymbols[syscore], 1.6, true, 3, getRandomInt(4000, 7000))
StockMarket[syscore] = syscoreStk;
var computek = Locations.VolhavenCompuTek;
var computekStk = new Stock(computek, StockSymbols[computek], 0.9, true, 4, getRandomInt(2000, 5000));
StockMarket[computek] = computekStk;
var netlink = Locations.AevumNetLinkTechnologies;
var netlinkStk = new Stock(netlink, StockSymbols[netlink], 4.2, true, 1, getRandomInt(2000, 4000));
StockMarket[netlink] = netlinkStk;
var omega = Locations.IshimaOmegaSoftware;
var omegaStk = new Stock(omega, StockSymbols[omega], 1, true, 0.5, getRandomInt(3000, 6000));
StockMarket[omega] = omegaStk;
var fns = Locations.Sector12FoodNStuff;
var fnsStk = new Stock(fns, StockSymbols[fns], 0.75, false, 1, getRandomInt(1000, 4000));
StockMarket[fns] = fnsStk;
var sigmacosm = "Sigma Cosmetics";
var sigmacosmStk = new Stock(sigmacosm, StockSymbols[sigmacosm], 2.8, true, 0, getRandomInt(2000, 3000));
StockMarket[sigmacosm] = sigmacosmStk;
var joesguns = "Joes Guns";
var joesgunsStk = new Stock(joesguns, StockSymbols[joesguns], 3.8, true, 1, getRandomInt(500, 1000));
StockMarket[joesguns] = joesgunsStk;
var catalyst = "Catalyst Ventures";
var catalystStk = new Stock(catalyst, StockSymbols[catalyst], 1.45, true, 13.5, getRandomInt(500, 1000));
StockMarket[catalyst] = catalystStk;
var microdyne = "Microdyne Technologies";
var microdyneStk = new Stock(microdyne, StockSymbols[microdyne], 0.75, true, 8, getRandomInt(20000, 25000));
StockMarket[microdyne] = microdyneStk;
var titanlabs = "Titan Laboratories";
var titanlabsStk = new Stock(titanlabs, StockSymbols[titanlabs], 0.6, true, 11, getRandomInt(15000, 20000));
StockMarket[titanlabs] = titanlabsStk;
var orders = {};
for (var name in StockMarket) {
if (StockMarket.hasOwnProperty(name)) {
var stock = StockMarket[name];
if (!(stock instanceof Stock)) {continue;}
orders[stock.symbol] = [];
}
}
StockMarket["Orders"] = orders;
}
function initSymbolToStockMap() {
for (var name in StockSymbols) {
if (StockSymbols.hasOwnProperty(name)) {
var stock = StockMarket[name];
if (stock == null) {
console.log("ERROR finding stock");
continue;
}
var symbol = StockSymbols[name];
SymbolToStockMap[symbol] = stock;
}
}
}
function stockMarketCycle() {
console.log("Cycling the Stock Market");
for (var name in StockMarket) {
if (StockMarket.hasOwnProperty(name)) {
var stock = StockMarket[name];
var thresh = 0.6;
if (stock.b) {thresh = 0.4;}
if (Math.random() < thresh) {
stock.b = !stock.b;
}
}
}
}
//Returns true if successful, false otherwise
function buyStock(stock, shares) {
if (stock == null || shares < 0 || isNaN(shares)) {
dialogBoxCreate("Failed to buy stock. This may be a bug, contact developer");
return false;
}
shares = Math.round(shares);
if (shares == 0) {return false;}
var totalPrice = stock.price * shares;
if (Player.money.lt(totalPrice + CONSTANTS.StockMarketCommission)) {
dialogBoxCreate("You do not have enough money to purchase this. You need $" +
formatNumber(totalPrice + CONSTANTS.StockMarketCommission, 2).toString() + ".");
return false;
}
var origTotal = stock.playerShares * stock.playerAvgPx;
Player.loseMoney(totalPrice + CONSTANTS.StockMarketCommission);
var newTotal = origTotal + totalPrice;
stock.playerShares += shares;
stock.playerAvgPx = newTotal / stock.playerShares;
updateStockPlayerPosition(stock);
dialogBoxCreate("Bought " + formatNumber(shares, 0) + " shares of " + stock.symbol + " at $" +
formatNumber(stock.price, 2) + " per share. You also paid $" +
formatNumber(CONSTANTS.StockMarketCommission, 2) + " in commission fees.");
return true;
}
//Returns true if successful and false otherwise
function sellStock(stock, shares) {
if (shares == 0) {return false;}
if (stock == null || shares < 0 || isNaN(shares)) {
dialogBoxCreate("Failed to sell stock. This may be a bug, contact developer");
return false;
}
shares = Math.round(shares);
if (shares > stock.playerShares) {shares = stock.playerShares;}
if (shares === 0) {return false;}
var gains = stock.price * shares - CONSTANTS.StockMarketCommission;
Player.gainMoney(gains);
stock.playerShares -= shares;
if (stock.playerShares == 0) {
stock.playerAvgPx = 0;
}
updateStockPlayerPosition(stock);
dialogBoxCreate("Sold " + formatNumber(shares, 0) + " shares of " + stock.symbol + " at $" +
formatNumber(stock.price, 2) + " per share. After commissions, you gained " +
"a total of $" + formatNumber(gains, 2));
return true;
}
//Returns true if successful and false otherwise
function shortStock(stock, shares, workerScript=null) {
var tixApi = (workerScript instanceof WorkerScript);
if (stock == null || isNaN(shares) || shares < 0) {
if (tixApi) {
workerScript.scriptRef.log("ERROR: shortStock() failed because of invalid arguments.");
} else {
dialogBoxCreate("Failed to initiate a short position in a stock. This is probably " +
"due to an invalid quantity. Otherwise, this may be a bug, so contact developer");
}
return false;
}
shares = Math.round(shares);
if (shares === 0) {return false;}
var totalPrice = stock.price * shares;
if (Player.money.lt(totalPrice + CONSTANTS.StockMarketCommission)) {
if (tixApi) {
workerScript.scriptRef.log("ERROR: shortStock() failed because you do not have " +
"money to purchase this short position. You need " +
numeral(totalPrice + CONSTANTS.StockMarketCommission).format('($0.000a)'));
} else {
dialogBoxCreate("You do not have enough money to purchase this short position. You need $" +
formatNumber(totalPrice + CONSTANTS.StockMarketCommission, 2) + ".");
}
return false;
}
var origTotal = stock.playerShortShares * stock.playerAvgShortPx;
Player.loseMoney(totalPrice + CONSTANTS.StockMarketCommission);
var newTotal = origTotal + totalPrice;
stock.playerShortShares += shares;
stock.playerAvgShortPx = newTotal / stock.playerShortShares;
updateStockPlayerPosition(stock);
if (tixApi) {
if (workerScript.disableLogs.ALL == null && workerScript.disableLogs.shortStock == null) {
workerScript.scriptRef.log("Bought a short position of " + formatNumber(shares, 0) + " shares of " + stock.symbol + " at " +
numeral(stock.price).format('($0.000a)') + " per share. Paid " +
numeral(CONSTANTS.StockMarketCommission).format('($0.000a)') + " in commission fees.");
}
} else {
dialogBoxCreate("Bought a short position of " + formatNumber(shares, 0) + " shares of " + stock.symbol + " at $" +
formatNumber(stock.price, 2) + " per share. You also paid $" +
formatNumber(CONSTANTS.StockMarketCommission, 2) + " in commission fees.");
}
return true;
}
//Returns true if successful and false otherwise
function sellShort(stock, shares, workerScript=null) {
var tixApi = (workerScript instanceof WorkerScript);
if (stock == null || isNaN(shares) || shares < 0) {
if (tixApi) {
workerScript.scriptRef.log("ERROR: sellShort() failed because of invalid arguments.");
} else {
dialogBoxCreate("Failed to sell a short position in a stock. This is probably " +
"due to an invalid quantity. Otherwise, this may be a bug, so contact developer");
}
return false;
}
shares = Math.round(shares);
if (shares > stock.playerShortShares) {shares = stock.playerShortShares;}
if (shares === 0) {return false;}
var origCost = shares * stock.playerAvgShortPx;
var profit = ((stock.playerAvgShortPx - stock.price) * shares) - CONSTANTS.StockMarketCommission;
if (isNaN(profit)) {profit = 0;}
Player.gainMoney(origCost + profit);
if (tixApi) {
workerScript.scriptRef.onlineMoneyMade += profit;
Player.scriptProdSinceLastAug += profit;
}
stock.playerShortShares -= shares;
if (stock.playerShortShares === 0) {
stock.playerAvgShortPx = 0;
}
updateStockPlayerPosition(stock);
if (tixApi) {
if (workerScript.disableLogs.ALL == null && workerScript.disableLogs.sellShort == null) {
workerScript.scriptRef.log("Sold your short position of " + shares + " shares of " + stock.symbol + " at " +
numeral(stock.price).format('($0.000a)') + " per share. After commissions, you gained " +
"a total of " + numeral(origCost + profit).format('($0.000a)'));
}
} else {
dialogBoxCreate("Sold your short position of " + formatNumber(shares, 0) + " shares of " + stock.symbol + " at $" +
formatNumber(stock.price, 2) + " per share. After commissions, you gained " +
"a total of $" + formatNumber(origCost + profit, 2));
}
return true;
}
function updateStockPrices() {
var v = Math.random();
for (var name in StockMarket) {
if (StockMarket.hasOwnProperty(name)) {
var stock = StockMarket[name];
if (!(stock instanceof Stock)) {continue;}
var av = (v * stock.mv) / 100;
if (isNaN(av)) {av = .02;}
var chc = 50;
if (stock.b) {
chc = (chc + stock.otlkMag)/100;
if (isNaN(chc)) {chc = 0.5;}
} else {
chc = (chc - stock.otlkMag)/100;
if (isNaN(chc)) {chc = 0.5;}
}
var c = Math.random();
if (c < chc) {
stock.price *= (1 + av);
processOrders(stock, OrderTypes.LimitBuy, PositionTypes.Short);
processOrders(stock, OrderTypes.LimitSell, PositionTypes.Long);
processOrders(stock, OrderTypes.StopBuy, PositionTypes.Long);
processOrders(stock, OrderTypes.StopSell, PositionTypes.Short);
if (Engine.currentPage == Engine.Page.StockMarket) {
updateStockTicker(stock, true);
}
} else {
stock.price /= (1 + av);
processOrders(stock, OrderTypes.LimitBuy, PositionTypes.Long);
processOrders(stock, OrderTypes.LimitSell, PositionTypes.Short);
processOrders(stock, OrderTypes.StopBuy, PositionTypes.Short);
processOrders(stock, OrderTypes.StopSell, PositionTypes.Long);
if (Engine.currentPage == Engine.Page.StockMarket) {
updateStockTicker(stock, false);
}
}
var otlkMagChange = stock.otlkMag * av;
if (stock.otlkMag <= 0.1) {
otlkMagChange = 1;
}
if (c < 0.5) {
stock.otlkMag += otlkMagChange;
} else {
stock.otlkMag -= otlkMagChange;
}
if (stock.otlkMag < 0) {
stock.otlkMag *= -1;
stock.b = !stock.b;
}
}
}
}
//Checks and triggers any orders for the specified stock
function processOrders(stock, orderType, posType) {
var orderBook = StockMarket["Orders"];
if (orderBook == null) {
var orders = {};
for (var name in StockMarket) {
if (StockMarket.hasOwnProperty(name)) {
var stock = StockMarket[name];
if (!(stock instanceof Stock)) {continue;}
orders[stock.symbol] = [];
}
}
StockMarket["Orders"] = orders;
return; //Newly created, so no orders to process
}
var stockOrders = orderBook[stock.symbol];
if (stockOrders == null || !(stockOrders.constructor === Array)) {
console.log("ERROR: Invalid Order book for " + stock.symbol + " in processOrders()");
stockOrders = [];
return;
}
for (var i = 0; i < stockOrders.length; ++i) {
var order = stockOrders[i];
if (order.type === orderType && order.pos === posType) {
switch(order.type) {
case OrderTypes.LimitBuy:
if (order.pos === PositionTypes.Long && stock.price <= order.price) {
executeOrder/*66*/(order);
} else if (order.pos === PositionTypes.Short && stock.price >= order.price) {
executeOrder/*66*/(order);
}
break;
case OrderTypes.LimitSell:
if (order.pos === PositionTypes.Long && stock.price >= order.price) {
executeOrder/*66*/(order);
} else if (order.pos === PositionTypes.Short && stock.price <= order.price) {
executeOrder/*66*/(order);
}
break;
case OrderTypes.StopBuy:
if (order.pos === PositionTypes.Long && stock.price >= order.price) {
executeOrder/*66*/(order);
} else if (order.pos === PositionTypes.Short && stock.price <= order.price) {
executeOrder/*66*/(order);
}
break;
case OrderTypes.StopSell:
if (order.pos === PositionTypes.Long && stock.price <= order.price) {
executeOrder/*66*/(order);
} else if (order.pos === PositionTypes.Short && stock.price >= order.price) {
executeOrder/*66*/(order);
}
break;
default:
console.log("Invalid order type: " + order.type);
return;
}
}
}
}
function setStockMarketContentCreated(b) {
stockMarketContentCreated = b;
}
var stockMarketContentCreated = false;
var stockMarketPortfolioMode = false;
var COMM = CONSTANTS.StockMarketCommission;
function displayStockMarketContent() {
if (Player.hasWseAccount == null) {Player.hasWseAccount = false;}
if (Player.hasTixApiAccess == null) {Player.hasTixApiAccess = false;}
//Purchase WSE Account button
var wseAccountButton = clearEventListeners("stock-market-buy-account");
wseAccountButton.innerText = "Buy WSE Account - $" + formatNumber(CONSTANTS.WSEAccountCost, 2).toString();
if (!Player.hasWseAccount && Player.money.gte(CONSTANTS.WSEAccountCost)) {
wseAccountButton.setAttribute("class", "a-link-button");
} else {
wseAccountButton.setAttribute("class", "a-link-button-inactive");
}
wseAccountButton.addEventListener("click", function() {
Player.hasWseAccount = true;
initStockMarket();
initSymbolToStockMap();
Player.loseMoney(CONSTANTS.WSEAccountCost);
displayStockMarketContent();
return false;
});
//Purchase TIX API Access account
var tixApiAccessButton = clearEventListeners("stock-market-buy-tix-api");
tixApiAccessButton.innerText = "Buy Trade Information eXchange (TIX) API Access - $" +
formatNumber(CONSTANTS.TIXAPICost, 2).toString();
if (!Player.hasTixApiAccess && Player.money.gte(CONSTANTS.TIXAPICost)) {
tixApiAccessButton.setAttribute("class", "a-link-button");
} else {
tixApiAccessButton.setAttribute("class", "a-link-button-inactive");
}
tixApiAccessButton.addEventListener("click", function() {
Player.hasTixApiAccess = true;
Player.loseMoney(CONSTANTS.TIXAPICost);
displayStockMarketContent();
return false;
});
var stockList = document.getElementById("stock-market-list");
if (stockList == null) {return;}
if (!Player.hasWseAccount) {
stockMarketContentCreated = false;
while (stockList.firstChild) {
stockList.removeChild(stockList.firstChild);
}
return;
}
//Create stock market content if you have an account
if (!stockMarketContentCreated && Player.hasWseAccount) {
console.log("Creating Stock Market UI");
document.getElementById("stock-market-commission").innerHTML =
"Commission Fees: Every transaction you make has a $" +
formatNumber(CONSTANTS.StockMarketCommission, 2) + " commission fee.
" +
"WARNING: When you reset after installing Augmentations, the Stock Market is reset. " +
"This means all your positions are lost, so make sure to sell your stocks before installing " +
"Augmentations!";
var investopediaButton = clearEventListeners("stock-market-investopedia");
investopediaButton.addEventListener("click", function() {
var txt = "When making a transaction on the stock market, there are two " +
"types of positions: Long and Short. A Long position is the typical " +
"scenario where you buy a stock and earn a profit if the price of that " +
"stock increases. Meanwhile, a Short position is the exact opposite. " +
"In a Short position you purchase shares of a stock and earn a profit " +
"if the price of that stock decreases. This is also called 'shorting' a stock.
" +
"NOTE: Shorting stocks is not available immediately, and must be unlocked later on in the game.
" +
"There are three different types of orders you can make to buy or sell " +
"stocks on the exchange: Market Order, Limit Order, and Stop Order. " +
"Note that Limit Orders and Stop Orders are not available immediately, and must be unlocked " +
"later on in the game.
" +
"When you place a Market Order to buy or sell a stock, the order executes " +
"immediately at whatever the current price of the stock is. For example " +
"if you choose to short a stock with 5000 shares using a Market Order, " +
"you immediately purchase those 5000 shares in a Short position at whatever " +
"the current market price is for that stock.
" +
"A Limit Order is an order that only executes under certain conditions. " +
"A Limit Order is used to buy or sell a stock at a specified price or better. " +
"For example, lets say you purchased a Long position of 100 shares of some stock " +
"at a price of $10 per share. You can place a Limit Order to sell those 100 shares " +
"at $50 or better. The Limit Order will execute when the price of the stock reaches a " +
"value of $50 or higher.
" +
"A Stop Order is the opposite of a Limit Order. It is used to buy or sell a stock " +
"at a specified price (before the price gets 'worse'). For example, lets say you purchased " +
"a Short position of 100 shares of some stock at a price of $100 per share. " +
"The current price of the stock is $80 (a profit of $20 per share). You can place a " +
"Stop Order to sell the Short position if the stock's price reaches $90 or higher. " +
"This can be used to lock in your profits and limit any losses.
" +
"Here is a summary of how each order works and when they execute:
" +
"In a LONG Position:
" +
"A Limit Order to buy will execute if the stock's price <= order's price
" +
"A Limit Order to sell will execute if the stock's price >= order's price
" +
"A Stop Order to buy will execute if the stock's price >= order's price
" +
"A Stop Order to sell will execute if the stock's price <= order's price
" +
"In a SHORT Position:
" +
"A Limit Order to buy will execute if the stock's price >= order's price
" +
"A Limit Order to sell will execute if the stock's price <= order's price
" +
"A Stop Order to buy will execute if the stock's price <= order's price
" +
"A Stop Order to sell will execute if the stock's price >= order's price.";
dialogBoxCreate(txt);
return false;
});
//Switch to Portfolio Mode Button
var modeBtn = clearEventListeners("stock-market-mode");
if (modeBtn) {
modeBtn.innerHTML = "Switch to 'Portfolio' Mode" +
"Displays only the stocks for which you have shares or orders";
modeBtn.addEventListener("click", switchToPortfolioMode);
}
//Expand/Collapse tickers buttons
var expandBtn = clearEventListeners("stock-market-expand-tickers"),
collapseBtn = clearEventListeners("stock-market-collapse-tickers"),
stockList = document.getElementById("stock-market-list");
if (expandBtn) {
expandBtn.addEventListener("click", ()=>{
var tickerHdrs = stockList.getElementsByClassName("accordion-header");
for (var i = 0; i < tickerHdrs.length; ++i) {
if (!tickerHdrs[i].classList.contains("active")) {
tickerHdrs[i].click();
}
}
});
}
if (collapseBtn) {
collapseBtn.addEventListener("click",()=>{
var tickerHdrs = stockList.getElementsByClassName("accordion-header");
for (var i = 0; i < tickerHdrs.length; ++i) {
if (tickerHdrs[i].classList.contains("active")) {
tickerHdrs[i].click();
}
}
});
}
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(); //Clicking headers opens/closes panels
stockMarketContentCreated = true;
}
if (Player.hasWseAccount) {
for (var name in StockMarket) {
if (StockMarket.hasOwnProperty(name)) {
var stock = StockMarket[name];
updateStockTicker(stock, null);
updateStockOrderList(stock);
}
}
}
}
//Displays only stocks you have position/order in
function switchToPortfolioMode() {
stockMarketPortfolioMode = true;
var stockList = document.getElementById("stock-market-list");
if (stockList == null) {return;}
var modeBtn = clearEventListeners("stock-market-mode");
if (modeBtn) {
modeBtn.innerHTML = "Switch to 'All stocks' Mode" +
"Displays all stocks on the WSE";
modeBtn.addEventListener("click", switchToDisplayAllMode);
}
while(stockList.firstChild) {stockList.removeChild(stockList.firstChild);}
//Get Order book (create it if it hasn't been created)
var orderBook = StockMarket["Orders"];
if (orderBook == null) {
var orders = {};
for (var name in StockMarket) {
if (StockMarket.hasOwnProperty(name)) {
var stock = StockMarket[name];
if (!(stock instanceof Stock)) {continue;}
orders[stock.symbol] = [];
}
}
StockMarket["Orders"] = orders;
}
for (var name in StockMarket) {
if (StockMarket.hasOwnProperty(name)) {
var stock = StockMarket[name];
if (!(stock instanceof Stock)) {continue;} //orders property is an array
var stockOrders = orderBook[stock.symbol];
if (stock.playerShares === 0 && stock.playerShortShares === 0 &&
stockOrders.length === 0) {continue;}
createStockTicker(stock);
}
}
setStockTickerClickHandlers();
}
//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" +
"Displays only the stocks for which you have shares or orders";
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) {
if (!(stock instanceof Stock)) {
console.log("Invalid stock in createStockSticker()");
return;
}
var tickerId = "stock-market-ticker-" + stock.symbol;
var li = document.createElement("li"), hdr = document.createElement("button");
hdr.classList.add("accordion-header");
hdr.setAttribute("id", tickerId + "-hdr");
hdr.innerHTML = stock.name + " - " + stock.symbol + " - $" + stock.price;
//Div for entire panel
var stockDiv = document.createElement("div");
stockDiv.classList.add("accordion-panel");
stockDiv.setAttribute("id", tickerId + "-panel");
/* Create panel DOM */
var qtyInput = document.createElement("input"),
longShortSelect = document.createElement("select"),
orderTypeSelect = document.createElement("select"),
buyButton = document.createElement("span"),
sellButton = document.createElement("span"),
buyMaxButton = document.createElement("span"),
sellAllButton = document.createElement("span"),
positionTxt = document.createElement("p"),
orderList = document.createElement("ul");
qtyInput.classList.add("stock-market-input");
qtyInput.placeholder = "Quantity (Shares)";
qtyInput.setAttribute("id", tickerId + "-qty-input");
qtyInput.setAttribute("onkeydown", "return ( event.ctrlKey || event.altKey " +
" || (4734 && event.keyCode<40) " +
" || (event.keyCode==46) )");
longShortSelect.classList.add("stock-market-input");
longShortSelect.setAttribute("id", tickerId + "-pos-selector");
var longOpt = document.createElement("option");
longOpt.text = "Long";
longShortSelect.add(longOpt);
if (Player.bitNodeN === 8 || (hasWallStreetSF && wallStreetSFLvl >= 2)) {
var shortOpt = document.createElement("option");
shortOpt.text = "Short";
longShortSelect.add(shortOpt);
}
orderTypeSelect.classList.add("stock-market-input");
orderTypeSelect.setAttribute("id", tickerId + "-order-selector");
var marketOpt = document.createElement("option");
marketOpt.text = "Market Order";
orderTypeSelect.add(marketOpt);
if (Player.bitNodeN === 8 || (hasWallStreetSF && wallStreetSFLvl >= 3)) {
var limitOpt = document.createElement("option");
limitOpt.text = "Limit Order";
orderTypeSelect.add(limitOpt);
var stopOpt = document.createElement("option");
stopOpt.text = "Stop Order";
orderTypeSelect.add(stopOpt);
}
buyButton.classList.add("stock-market-input");
buyButton.classList.add("a-link-button");
buyButton.innerHTML = "Buy";
buyButton.addEventListener("click", ()=>{
var pos = longShortSelect.options[longShortSelect.selectedIndex].text;
pos === "Long" ? pos = PositionTypes.Long : pos = PositionTypes.Short;
var ordType = orderTypeSelect.options[orderTypeSelect.selectedIndex].text;
var shares = Number(document.getElementById(tickerId + "-qty-input").value);
if (isNaN(shares)) {return false;}
switch (ordType) {
case "Market Order":
pos === PositionTypes.Long ? buyStock(stock, shares) : shortStock(stock, shares, null);
break;
case "Limit Order":
case "Stop Order":
var yesBtn = yesNoTxtInpBoxGetYesButton(),
noBtn = yesNoTxtInpBoxGetNoButton();
yesBtn.innerText = "Place Buy " + ordType;
noBtn.innerText = "Cancel Order";
yesBtn.addEventListener("click", ()=>{
var price = Number(yesNoTxtInpBoxGetInput()), type;
if (ordType === "Limit Order") {
type = OrderTypes.LimitBuy;
} else {
type = OrderTypes.StopBuy;
}
placeOrder(stock, shares, price, type, pos);
yesNoTxtInpBoxClose();
});
noBtn.addEventListener("click", ()=>{
yesNoTxtInpBoxClose();
});
yesNoTxtInpBoxCreate("Enter the price for your " + ordType);
break;
default:
console.log("ERROR: Invalid order type");
break;
}
return false;
});
sellButton.classList.add("stock-market-input");
sellButton.classList.add("a-link-button");
sellButton.innerHTML = "Sell";
sellButton.addEventListener("click", ()=>{
var pos = longShortSelect.options[longShortSelect.selectedIndex].text;
pos === "Long" ? pos = PositionTypes.Long : pos = PositionTypes.Short;
var ordType = orderTypeSelect.options[orderTypeSelect.selectedIndex].text;
var shares = Number(document.getElementById(tickerId + "-qty-input").value);
if (isNaN(shares)) {return false;}
switch (ordType) {
case "Market Order":
pos === PositionTypes.Long ? sellStock(stock, shares) : sellShort(stock, shares, null);
break;
case "Limit Order":
case "Stop Order":
var yesBtn = yesNoTxtInpBoxGetYesButton(),
noBtn = yesNoTxtInpBoxGetNoButton();
yesBtn.innerText = "Place Sell " + ordType;
noBtn.innerText = "Cancel Order";
yesBtn.addEventListener("click", ()=>{
var price = Number(yesNoTxtInpBoxGetInput()), type;
if (ordType === "Limit Order") {
type = OrderTypes.LimitSell;
} else {
type = OrderTypes.StopSell;
}
yesNoTxtInpBoxClose();
placeOrder(stock, shares, price, type, pos);
});
noBtn.addEventListener("click", ()=>{
yesNoTxtInpBoxClose();
});
yesNoTxtInpBoxCreate("Enter the price for your " + ordType);
break;
default:
console.log("ERROR: Invalid order type");
break;
}
return false;
});
buyMaxButton.classList.add("stock-market-input");
buyMaxButton.classList.add("a-link-button");
buyMaxButton.innerHTML = "Buy MAX";
buyMaxButton.addEventListener("click", ()=>{
var pos = longShortSelect.options[longShortSelect.selectedIndex].text;
pos === "Long" ? pos = PositionTypes.Long : pos = PositionTypes.Short;
var ordType = orderTypeSelect.options[orderTypeSelect.selectedIndex].text;
var money = Player.money.toNumber();
switch (ordType) {
case "Market Order":
var shares = Math.floor((money - COMM) / stock.price);
pos === PositionTypes.Long ? buyStock(stock, shares) : shortStock(stock, shares, null);
break;
case "Limit Order":
case "Stop Order":
var yesBtn = yesNoTxtInpBoxGetYesButton(),
noBtn = yesNoTxtInpBoxGetNoButton();
yesBtn.innerText = "Place Buy " + ordType;
noBtn.innerText = "Cancel Order";
yesBtn.addEventListener("click", ()=>{
var price = Number(yesNoTxtInpBoxGetInput()), type;
if (ordType === "Limit Order") {
type = OrderTypes.LimitBuy;
} else {
type = OrderTypes.StopBuy;
}
var shares = Math.floor((money-COMM) / price);
placeOrder(stock, shares, price, type, pos);
yesNoTxtInpBoxClose();
});
noBtn.addEventListener("click", ()=>{
yesNoTxtInpBoxClose();
});
yesNoTxtInpBoxCreate("Enter the price for your " + ordType);
break;
default:
console.log("ERROR: Invalid order type");
break;
}
return false;
});
sellAllButton.classList.add("stock-market-input");
sellAllButton.classList.add("a-link-button");
sellAllButton.innerHTML = "Sell ALL";
sellAllButton.addEventListener("click", ()=>{
var pos = longShortSelect.options[longShortSelect.selectedIndex].text;
pos === "Long" ? pos = PositionTypes.Long : pos = PositionTypes.Short;
var ordType = orderTypeSelect.options[orderTypeSelect.selectedIndex].text;
switch (ordType) {
case "Market Order":
if (pos === PositionTypes.Long) {
var shares = stock.playerShares;
sellStock(stock, shares);
} else {
var shares = stock.playerShortShares;
sellShort(stock, shares, null);
}
break;
case "Limit Order":
case "Stop Order":
dialogBoxCreate("ERROR: 'Sell All' only works for Market Orders")
break;
default:
console.log("ERROR: Invalid order type");
break;
}
return false;
});
positionTxt.setAttribute("id", tickerId + "-position-text");
positionTxt.classList.add("stock-market-position-text");
stock.posTxtEl = positionTxt;
orderList.setAttribute("id", tickerId + "-order-list");
orderList.classList.add("stock-market-order-list");
stockDiv.appendChild(qtyInput);
stockDiv.appendChild(longShortSelect);
stockDiv.appendChild(orderTypeSelect);
stockDiv.appendChild(buyButton);
stockDiv.appendChild(sellButton);
stockDiv.appendChild(buyMaxButton);
stockDiv.appendChild(sellAllButton);
stockDiv.appendChild(positionTxt);
stockDiv.appendChild(orderList);
li.appendChild(hdr);
li.appendChild(stockDiv);
document.getElementById("stock-market-list").appendChild(li);
updateStockTicker(stock, true);
updateStockPlayerPosition(stock);
updateStockOrderList(stock);
}
function setStockTickerClickHandlers() {
var stockList = document.getElementById("stock-market-list");
var tickerHdrs = stockList.getElementsByClassName("accordion-header");
if (tickerHdrs == null) {
console.log("ERROR: Could not find header elements for stock tickers");
return;
}
for (var i = 0; i < tickerHdrs.length; ++i) {
tickerHdrs[i].onclick = function() {
this.classList.toggle("active");
var panel = this.nextElementSibling;
if (panel.style.display === "block") {
panel.style.display = "none";
} else {
panel.style.display = "block";
}
}
}
}
//'increase' argument is a boolean indicating whether the price increased or decreased
function updateStockTicker(stock, increase) {
if (Engine.currentPage !== Engine.Page.StockMarket) {return;}
if (!(stock instanceof Stock)) {
console.log("Invalid stock in updateStockTicker():");
console.log(stock);
return;
}
var tickerId = "stock-market-ticker-" + stock.symbol;
if (stock.playerShares > 0 || stock.playerShortShares > 0) {
updateStockPlayerPosition(stock);
}
var hdr = document.getElementById(tickerId + "-hdr");
if (hdr == null) {
if (!stockMarketPortfolioMode) {console.log("ERROR: Couldn't find ticker element for stock: " + stock.symbol);}
return;
}
hdr.innerHTML = stock.name + " - " + stock.symbol + " - $" + formatNumber(stock.price, 2);
if (increase != null) {
increase ? hdr.style.color = "#66ff33" : hdr.style.color = "red";
}
}
function updateStockPlayerPosition(stock) {
if (Engine.currentPage !== Engine.Page.StockMarket) {return;}
if (!(stock instanceof Stock)) {
console.log("Invalid stock in updateStockPlayerPosition():");
console.log(stock);
return;
}
var tickerId = "stock-market-ticker-" + stock.symbol;
if (stockMarketPortfolioMode) {
if (stock.playerShares === 0 && stock.playerShortShares === 0 &&
StockMarket["Orders"] && StockMarket["Orders"][stock.symbol] &&
StockMarket["Orders"][stock.symbol].length === 0) {
removeElementById(tickerId + "-hdr");
removeElementById(tickerId + "-panel");
return;
} else {
//If the ticker hasn't been created, create it (handles updating)
//If it has been created, continue normally
if (document.getElementById(tickerId + "-hdr") == null) {
createStockTicker(stock);
setStockTickerClickHandlers();
return;
}
}
}
if (!(stock.posTxtEl instanceof Element)) {
stock.posTxtEl = document.getElementById(tickerId + "-position-text");
}
if (stock.posTxtEl == null) {
console.log("ERROR: Could not find stock position element for: " + stock.symbol);
return;
}
//Calculate returns
var totalCost = stock.playerShares * stock.playerAvgPx,
gains = (stock.price - stock.playerAvgPx) * stock.playerShares,
percentageGains = gains / totalCost;
if (isNaN(percentageGains)) {percentageGains = 0;}
var shortTotalCost = stock.playerShortShares * stock.playerAvgShortPx,
shortGains = (stock.playerAvgShortPx - stock.price) * stock.playerShortShares,
shortPercentageGains = shortGains/ shortTotalCost;
if (isNaN(shortPercentageGains)) {shortPercentageGains = 0;}
stock.posTxtEl.innerHTML =
"Long Position: " +
"Shares in the long position will increase " +
"in value if the price of the corresponding stock increases
" +
"
Shares: " + formatNumber(stock.playerShares, 0) +
"
Average Price: " + numeral(stock.playerAvgPx).format('$0.000a') +
" (Total Cost: " + numeral(totalCost).format('$0.000a') + ")" +
"
Profit: " + numeral(gains).format('$0.000a') +
" (" + formatNumber(percentageGains*100, 2) + "%)
";
if (Player.bitNodeN === 8 || (hasWallStreetSF && wallStreetSFLvl >= 2)) {
stock.posTxtEl.innerHTML +=
"Short Position: " +
"Shares in short position will increase " +
"in value if the price of the corresponding stock decreases
" +
"
Shares: " + formatNumber(stock.playerShortShares, 0) +
"
Average Price: " + numeral(stock.playerAvgShortPx).format('$0.000a') +
" (Total Cost: " + numeral(shortTotalCost).format('$0.000a') + ")" +
"
Profit: " + numeral(shortGains).format('$0.000a') +
" (" + formatNumber(shortPercentageGains*100, 2) + "%)" +
"
Orders:
";
}
}
function updateStockOrderList(stock) {
if (Engine.currentPage !== Engine.Page.StockMarket) {return;}
var tickerId = "stock-market-ticker-" + stock.symbol;
var orderList = document.getElementById(tickerId + "-order-list");
if (orderList == null) {
if (!stockMarketPortfolioMode) {console.log("ERROR: Could not find order list for " + stock.symbol);}
return;
}
var orderBook = StockMarket["Orders"];
if (orderBook == null) {
console.log("ERROR: Could not find order book in stock market");
return;
}
var stockOrders = orderBook[stock.symbol];
if (stockOrders == null) {
console.log("ERROR: Could not find orders for: " + stock.symbol);
return;
}
if (stockMarketPortfolioMode) {
if (stock.playerShares === 0 && stock.playerShortShares === 0 &&
StockMarket["Orders"] && StockMarket["Orders"][stock.symbol] &&
StockMarket["Orders"][stock.symbol].length === 0) {
removeElementById(tickerId + "-hdr");
removeElementById(tickerId + "-panel");
return;
} else {
//If the ticker hasn't been created, create it (handles updating)
//If it has been created, continue normally
if (document.getElementById(tickerId + "-hdr") == null) {
createStockTicker(stock);
setStockTickerClickHandlers();
return;
}
}
}
//Remove everything from list
while (orderList.firstChild) {
orderList.removeChild(orderList.firstChild);
}
for (var i = 0; i < stockOrders.length; ++i) {
(function() {
var order = stockOrders[i];
var li = document.createElement("li");
li.style.padding = "4px";
var posText = (order.pos === PositionTypes.Long ? "Long Position" : "Short Position");
li.style.color = "white";
li.innerText = order.type + " - " + posText + " - " +
order.shares + " @ $" + formatNumber(order.price, 2);
var cancelButton = document.createElement("span");
cancelButton.classList.add("stock-market-order-cancel-btn");
cancelButton.classList.add("a-link-button");
cancelButton.innerHTML = "Cancel Order";
cancelButton.addEventListener("click", function() {
cancelOrder({order: order}, null);
return false;
});
li.appendChild(cancelButton);
orderList.appendChild(li);
}());
}
}
export {StockMarket, StockSymbols, SymbolToStockMap, initStockSymbols,
initStockMarket, initSymbolToStockMap, stockMarketCycle, buyStock,
sellStock, shortStock, sellShort, updateStockPrices, displayStockMarketContent,
updateStockTicker, updateStockPlayerPosition, loadStockMarket,
setStockMarketContentCreated, placeOrder, cancelOrder, Order, OrderTypes, PositionTypes};