2021-10-14 09:22:02 +02:00
|
|
|
import { INetscriptHelper } from "./INetscriptHelper";
|
|
|
|
import { WorkerScript } from "../Netscript/WorkerScript";
|
|
|
|
import { IPlayer } from "../PersonObjects/IPlayer";
|
|
|
|
import { getRamCost } from "../Netscript/RamCostGenerator";
|
|
|
|
import { buyStock, sellStock, shortStock, sellShort } from "../StockMarket/BuyingAndSelling";
|
|
|
|
import { StockMarket, SymbolToStockMap, placeOrder, cancelOrder } from "../StockMarket/StockMarket";
|
|
|
|
import { getBuyTransactionCost, getSellTransactionGain } from "../StockMarket/StockMarketHelpers";
|
|
|
|
import { OrderTypes } from "../StockMarket/data/OrderTypes";
|
|
|
|
import { PositionTypes } from "../StockMarket/data/PositionTypes";
|
|
|
|
import { StockSymbols } from "../StockMarket/data/StockSymbols";
|
2022-03-19 04:58:18 +01:00
|
|
|
import { getStockMarket4SDataCost, getStockMarket4STixApiCost, getStockMarketWseCost, getStockMarketTixApiCost } from "../StockMarket/StockMarketCosts";
|
2021-10-14 09:22:02 +02:00
|
|
|
import { Stock } from "../StockMarket/Stock";
|
2021-10-30 22:03:34 +02:00
|
|
|
import { TIX } from "../ScriptEditor/NetscriptDefinitions";
|
2021-10-14 09:22:02 +02:00
|
|
|
|
2021-10-30 22:03:34 +02:00
|
|
|
export function NetscriptStockMarket(player: IPlayer, workerScript: WorkerScript, helper: INetscriptHelper): TIX {
|
2021-10-14 09:22:02 +02:00
|
|
|
/**
|
|
|
|
* Checks if the player has TIX API access. Throws an error if the player does not
|
|
|
|
*/
|
|
|
|
const checkTixApiAccess = function (callingFn: string): void {
|
|
|
|
if (!player.hasWseAccount) {
|
|
|
|
throw helper.makeRuntimeErrorMsg(callingFn, `You don't have WSE Access! Cannot use ${callingFn}()`);
|
|
|
|
}
|
|
|
|
if (!player.hasTixApiAccess) {
|
|
|
|
throw helper.makeRuntimeErrorMsg(callingFn, `You don't have TIX API Access! Cannot use ${callingFn}()`);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
const getStockFromSymbol = function (symbol: string, callingFn: string): Stock {
|
|
|
|
const stock = SymbolToStockMap[symbol];
|
|
|
|
if (stock == null) {
|
|
|
|
throw helper.makeRuntimeErrorMsg(callingFn, `Invalid stock symbol: '${symbol}'`);
|
|
|
|
}
|
|
|
|
|
|
|
|
return stock;
|
|
|
|
};
|
|
|
|
return {
|
2022-03-17 19:00:22 +01:00
|
|
|
getSymbols: function (): string[] {
|
2022-01-05 01:09:34 +01:00
|
|
|
helper.updateDynamicRam("getSymbols", getRamCost(player, "stock", "getSymbols"));
|
2021-10-27 21:16:16 +02:00
|
|
|
checkTixApiAccess("getSymbols");
|
2021-10-14 09:22:02 +02:00
|
|
|
return Object.values(StockSymbols);
|
|
|
|
},
|
2022-03-17 19:00:22 +01:00
|
|
|
getPrice: function (_symbol: unknown): number {
|
|
|
|
const symbol = helper.string("getPrice", "symbol", _symbol);
|
2022-01-05 01:09:34 +01:00
|
|
|
helper.updateDynamicRam("getPrice", getRamCost(player, "stock", "getPrice"));
|
2021-10-27 21:16:16 +02:00
|
|
|
checkTixApiAccess("getPrice");
|
|
|
|
const stock = getStockFromSymbol(symbol, "getPrice");
|
2021-10-14 09:22:02 +02:00
|
|
|
|
|
|
|
return stock.price;
|
|
|
|
},
|
2022-03-17 19:00:22 +01:00
|
|
|
getAskPrice: function (_symbol: unknown): number {
|
|
|
|
const symbol = helper.string("getAskPrice", "symbol", _symbol);
|
2022-01-05 01:09:34 +01:00
|
|
|
helper.updateDynamicRam("getAskPrice", getRamCost(player, "stock", "getAskPrice"));
|
2021-10-27 21:16:16 +02:00
|
|
|
checkTixApiAccess("getAskPrice");
|
|
|
|
const stock = getStockFromSymbol(symbol, "getAskPrice");
|
2021-10-14 09:22:02 +02:00
|
|
|
|
|
|
|
return stock.getAskPrice();
|
|
|
|
},
|
2022-03-17 19:00:22 +01:00
|
|
|
getBidPrice: function (_symbol: unknown): number {
|
|
|
|
const symbol = helper.string("getBidPrice", "symbol", _symbol);
|
2022-01-05 01:09:34 +01:00
|
|
|
helper.updateDynamicRam("getBidPrice", getRamCost(player, "stock", "getBidPrice"));
|
2021-10-27 21:16:16 +02:00
|
|
|
checkTixApiAccess("getBidPrice");
|
|
|
|
const stock = getStockFromSymbol(symbol, "getBidPrice");
|
2021-10-14 09:22:02 +02:00
|
|
|
|
|
|
|
return stock.getBidPrice();
|
|
|
|
},
|
2022-03-17 19:00:22 +01:00
|
|
|
getPosition: function (_symbol: unknown): [number, number, number, number] {
|
|
|
|
const symbol = helper.string("getPosition", "symbol", _symbol);
|
2022-01-05 01:09:34 +01:00
|
|
|
helper.updateDynamicRam("getPosition", getRamCost(player, "stock", "getPosition"));
|
2021-10-27 21:16:16 +02:00
|
|
|
checkTixApiAccess("getPosition");
|
2021-10-14 09:22:02 +02:00
|
|
|
const stock = SymbolToStockMap[symbol];
|
|
|
|
if (stock == null) {
|
2021-10-27 21:16:16 +02:00
|
|
|
throw helper.makeRuntimeErrorMsg("getPosition", `Invalid stock symbol: ${symbol}`);
|
2021-10-14 09:22:02 +02:00
|
|
|
}
|
|
|
|
return [stock.playerShares, stock.playerAvgPx, stock.playerShortShares, stock.playerAvgShortPx];
|
|
|
|
},
|
2022-03-17 19:00:22 +01:00
|
|
|
getMaxShares: function (_symbol: unknown): number {
|
|
|
|
const symbol = helper.string("getMaxShares", "symbol", _symbol);
|
2022-01-05 01:09:34 +01:00
|
|
|
helper.updateDynamicRam("getMaxShares", getRamCost(player, "stock", "getMaxShares"));
|
2021-10-27 21:16:16 +02:00
|
|
|
checkTixApiAccess("getMaxShares");
|
|
|
|
const stock = getStockFromSymbol(symbol, "getMaxShares");
|
2021-10-14 09:22:02 +02:00
|
|
|
|
|
|
|
return stock.maxShares;
|
|
|
|
},
|
2022-03-17 19:00:22 +01:00
|
|
|
getPurchaseCost: function (_symbol: unknown, _shares: unknown, _posType: unknown): number {
|
|
|
|
const symbol = helper.string("getPurchaseCost", "symbol", _symbol);
|
|
|
|
let shares = helper.number("getPurchaseCost", "shares", _shares);
|
|
|
|
const posType = helper.string("getPurchaseCost", "posType", _posType);
|
2022-01-05 01:09:34 +01:00
|
|
|
helper.updateDynamicRam("getPurchaseCost", getRamCost(player, "stock", "getPurchaseCost"));
|
2021-10-27 21:16:16 +02:00
|
|
|
checkTixApiAccess("getPurchaseCost");
|
|
|
|
const stock = getStockFromSymbol(symbol, "getPurchaseCost");
|
2021-10-14 09:22:02 +02:00
|
|
|
shares = Math.round(shares);
|
|
|
|
|
|
|
|
let pos;
|
|
|
|
const sanitizedPosType = posType.toLowerCase();
|
|
|
|
if (sanitizedPosType.includes("l")) {
|
|
|
|
pos = PositionTypes.Long;
|
|
|
|
} else if (sanitizedPosType.includes("s")) {
|
|
|
|
pos = PositionTypes.Short;
|
|
|
|
} else {
|
|
|
|
return Infinity;
|
|
|
|
}
|
|
|
|
|
|
|
|
const res = getBuyTransactionCost(stock, shares, pos);
|
|
|
|
if (res == null) {
|
|
|
|
return Infinity;
|
|
|
|
}
|
|
|
|
|
|
|
|
return res;
|
|
|
|
},
|
2022-03-17 19:00:22 +01:00
|
|
|
getSaleGain: function (_symbol: unknown, _shares: unknown, _posType: unknown): number {
|
|
|
|
const symbol = helper.string("getSaleGain", "symbol", _symbol);
|
|
|
|
let shares = helper.number("getSaleGain", "shares", _shares);
|
|
|
|
const posType = helper.string("getSaleGain", "posType", _posType);
|
2022-01-05 01:09:34 +01:00
|
|
|
helper.updateDynamicRam("getSaleGain", getRamCost(player, "stock", "getSaleGain"));
|
2021-10-27 21:16:16 +02:00
|
|
|
checkTixApiAccess("getSaleGain");
|
|
|
|
const stock = getStockFromSymbol(symbol, "getSaleGain");
|
2021-10-14 09:22:02 +02:00
|
|
|
shares = Math.round(shares);
|
|
|
|
|
|
|
|
let pos;
|
|
|
|
const sanitizedPosType = posType.toLowerCase();
|
|
|
|
if (sanitizedPosType.includes("l")) {
|
|
|
|
pos = PositionTypes.Long;
|
|
|
|
} else if (sanitizedPosType.includes("s")) {
|
|
|
|
pos = PositionTypes.Short;
|
|
|
|
} else {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
const res = getSellTransactionGain(stock, shares, pos);
|
|
|
|
if (res == null) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return res;
|
|
|
|
},
|
2022-03-17 19:00:22 +01:00
|
|
|
buy: function (_symbol: unknown, _shares: unknown): number {
|
|
|
|
const symbol = helper.string("buy", "symbol", _symbol);
|
|
|
|
const shares = helper.number("buy", "shares", _shares);
|
2022-01-05 01:09:34 +01:00
|
|
|
helper.updateDynamicRam("buy", getRamCost(player, "stock", "buy"));
|
2021-10-27 21:16:16 +02:00
|
|
|
checkTixApiAccess("buy");
|
|
|
|
const stock = getStockFromSymbol(symbol, "buy");
|
2021-10-14 09:22:02 +02:00
|
|
|
const res = buyStock(stock, shares, workerScript, {});
|
2021-11-19 20:39:38 +01:00
|
|
|
return res ? stock.getAskPrice() : 0;
|
2021-10-14 09:22:02 +02:00
|
|
|
},
|
2022-03-17 19:00:22 +01:00
|
|
|
sell: function (_symbol: unknown, _shares: unknown): number {
|
|
|
|
const symbol = helper.string("sell", "symbol", _symbol);
|
|
|
|
const shares = helper.number("sell", "shares", _shares);
|
2022-01-05 01:09:34 +01:00
|
|
|
helper.updateDynamicRam("sell", getRamCost(player, "stock", "sell"));
|
2021-10-27 21:16:16 +02:00
|
|
|
checkTixApiAccess("sell");
|
|
|
|
const stock = getStockFromSymbol(symbol, "sell");
|
2021-10-14 09:22:02 +02:00
|
|
|
const res = sellStock(stock, shares, workerScript, {});
|
|
|
|
|
2021-11-19 20:39:38 +01:00
|
|
|
return res ? stock.getBidPrice() : 0;
|
2021-10-14 09:22:02 +02:00
|
|
|
},
|
2022-03-17 19:00:22 +01:00
|
|
|
short: function (_symbol: unknown, _shares: unknown): number {
|
|
|
|
const symbol = helper.string("short", "symbol", _symbol);
|
|
|
|
const shares = helper.number("short", "shares", _shares);
|
2022-01-05 01:09:34 +01:00
|
|
|
helper.updateDynamicRam("short", getRamCost(player, "stock", "short"));
|
2021-10-27 21:16:16 +02:00
|
|
|
checkTixApiAccess("short");
|
2021-10-14 09:22:02 +02:00
|
|
|
if (player.bitNodeN !== 8) {
|
|
|
|
if (player.sourceFileLvl(8) <= 1) {
|
|
|
|
throw helper.makeRuntimeErrorMsg(
|
2021-10-27 21:16:16 +02:00
|
|
|
"short",
|
2021-10-14 09:22:02 +02:00
|
|
|
"You must either be in BitNode-8 or you must have Source-File 8 Level 2.",
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
2021-10-27 21:16:16 +02:00
|
|
|
const stock = getStockFromSymbol(symbol, "short");
|
2021-10-14 09:22:02 +02:00
|
|
|
const res = shortStock(stock, shares, workerScript, {});
|
|
|
|
|
2021-11-22 16:19:23 +01:00
|
|
|
return res ? stock.getBidPrice() : 0;
|
2021-10-14 09:22:02 +02:00
|
|
|
},
|
2022-03-17 19:00:22 +01:00
|
|
|
sellShort: function (_symbol: unknown, _shares: unknown): number {
|
|
|
|
const symbol = helper.string("sellShort", "symbol", _symbol);
|
|
|
|
const shares = helper.number("sellShort", "shares", _shares);
|
2022-01-05 01:09:34 +01:00
|
|
|
helper.updateDynamicRam("sellShort", getRamCost(player, "stock", "sellShort"));
|
2021-10-14 09:22:02 +02:00
|
|
|
checkTixApiAccess("sellShort");
|
|
|
|
if (player.bitNodeN !== 8) {
|
|
|
|
if (player.sourceFileLvl(8) <= 1) {
|
|
|
|
throw helper.makeRuntimeErrorMsg(
|
|
|
|
"sellShort",
|
|
|
|
"You must either be in BitNode-8 or you must have Source-File 8 Level 2.",
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
const stock = getStockFromSymbol(symbol, "sellShort");
|
|
|
|
const res = sellShort(stock, shares, workerScript, {});
|
|
|
|
|
2021-11-22 16:19:23 +01:00
|
|
|
return res ? stock.getAskPrice() : 0;
|
2021-10-14 09:22:02 +02:00
|
|
|
},
|
2022-03-17 19:00:22 +01:00
|
|
|
placeOrder: function (_symbol: unknown, _shares: unknown, _price: unknown, _type: unknown, _pos: unknown): boolean {
|
|
|
|
const symbol = helper.string("placeOrder", "symbol", _symbol);
|
|
|
|
const shares = helper.number("placeOrder", "shares", _shares);
|
|
|
|
const price = helper.number("placeOrder", "price", _price);
|
|
|
|
const type = helper.string("placeOrder", "type", _type);
|
|
|
|
const pos = helper.string("placeOrder", "pos", _pos);
|
2022-01-05 01:09:34 +01:00
|
|
|
helper.updateDynamicRam("placeOrder", getRamCost(player, "stock", "placeOrder"));
|
2021-10-14 09:22:02 +02:00
|
|
|
checkTixApiAccess("placeOrder");
|
|
|
|
if (player.bitNodeN !== 8) {
|
|
|
|
if (player.sourceFileLvl(8) <= 2) {
|
|
|
|
throw helper.makeRuntimeErrorMsg(
|
|
|
|
"placeOrder",
|
|
|
|
"You must either be in BitNode-8 or you must have Source-File 8 Level 3.",
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
const stock = getStockFromSymbol(symbol, "placeOrder");
|
|
|
|
|
|
|
|
let orderType;
|
|
|
|
let orderPos;
|
|
|
|
const ltype = type.toLowerCase();
|
|
|
|
if (ltype.includes("limit") && ltype.includes("buy")) {
|
|
|
|
orderType = OrderTypes.LimitBuy;
|
|
|
|
} else if (ltype.includes("limit") && ltype.includes("sell")) {
|
|
|
|
orderType = OrderTypes.LimitSell;
|
|
|
|
} else if (ltype.includes("stop") && ltype.includes("buy")) {
|
|
|
|
orderType = OrderTypes.StopBuy;
|
|
|
|
} else if (ltype.includes("stop") && ltype.includes("sell")) {
|
|
|
|
orderType = OrderTypes.StopSell;
|
|
|
|
} else {
|
|
|
|
throw helper.makeRuntimeErrorMsg("placeOrder", `Invalid order type: ${type}`);
|
|
|
|
}
|
|
|
|
|
|
|
|
const lpos = pos.toLowerCase();
|
|
|
|
if (lpos.includes("l")) {
|
|
|
|
orderPos = PositionTypes.Long;
|
|
|
|
} else if (lpos.includes("s")) {
|
|
|
|
orderPos = PositionTypes.Short;
|
|
|
|
} else {
|
|
|
|
throw helper.makeRuntimeErrorMsg("placeOrder", `Invalid position type: ${pos}`);
|
|
|
|
}
|
|
|
|
|
|
|
|
return placeOrder(stock, shares, price, orderType, orderPos, workerScript);
|
|
|
|
},
|
2022-03-17 19:00:22 +01:00
|
|
|
cancelOrder: function (
|
|
|
|
_symbol: unknown,
|
|
|
|
_shares: unknown,
|
|
|
|
_price: unknown,
|
|
|
|
_type: unknown,
|
|
|
|
_pos: unknown,
|
|
|
|
): boolean {
|
|
|
|
const symbol = helper.string("cancelOrder", "symbol", _symbol);
|
|
|
|
const shares = helper.number("cancelOrder", "shares", _shares);
|
|
|
|
const price = helper.number("cancelOrder", "price", _price);
|
|
|
|
const type = helper.string("cancelOrder", "type", _type);
|
|
|
|
const pos = helper.string("cancelOrder", "pos", _pos);
|
2022-01-05 01:09:34 +01:00
|
|
|
helper.updateDynamicRam("cancelOrder", getRamCost(player, "stock", "cancelOrder"));
|
2021-10-14 09:22:02 +02:00
|
|
|
checkTixApiAccess("cancelOrder");
|
|
|
|
if (player.bitNodeN !== 8) {
|
|
|
|
if (player.sourceFileLvl(8) <= 2) {
|
|
|
|
throw helper.makeRuntimeErrorMsg(
|
|
|
|
"cancelOrder",
|
|
|
|
"You must either be in BitNode-8 or you must have Source-File 8 Level 3.",
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
const stock = getStockFromSymbol(symbol, "cancelOrder");
|
|
|
|
if (isNaN(shares) || isNaN(price)) {
|
|
|
|
throw helper.makeRuntimeErrorMsg(
|
|
|
|
"cancelOrder",
|
|
|
|
`Invalid shares or price. Must be numeric. shares=${shares}, price=${price}`,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
let orderType;
|
|
|
|
let orderPos;
|
|
|
|
const ltype = type.toLowerCase();
|
|
|
|
if (ltype.includes("limit") && ltype.includes("buy")) {
|
|
|
|
orderType = OrderTypes.LimitBuy;
|
|
|
|
} else if (ltype.includes("limit") && ltype.includes("sell")) {
|
|
|
|
orderType = OrderTypes.LimitSell;
|
|
|
|
} else if (ltype.includes("stop") && ltype.includes("buy")) {
|
|
|
|
orderType = OrderTypes.StopBuy;
|
|
|
|
} else if (ltype.includes("stop") && ltype.includes("sell")) {
|
|
|
|
orderType = OrderTypes.StopSell;
|
|
|
|
} else {
|
|
|
|
throw helper.makeRuntimeErrorMsg("cancelOrder", `Invalid order type: ${type}`);
|
|
|
|
}
|
|
|
|
|
|
|
|
const lpos = pos.toLowerCase();
|
|
|
|
if (lpos.includes("l")) {
|
|
|
|
orderPos = PositionTypes.Long;
|
|
|
|
} else if (lpos.includes("s")) {
|
|
|
|
orderPos = PositionTypes.Short;
|
|
|
|
} else {
|
|
|
|
throw helper.makeRuntimeErrorMsg("cancelOrder", `Invalid position type: ${pos}`);
|
|
|
|
}
|
|
|
|
const params = {
|
|
|
|
stock: stock,
|
|
|
|
shares: shares,
|
|
|
|
price: price,
|
|
|
|
type: orderType,
|
|
|
|
pos: orderPos,
|
|
|
|
};
|
|
|
|
return cancelOrder(params, workerScript);
|
|
|
|
},
|
|
|
|
getOrders: function (): any {
|
2022-01-05 01:09:34 +01:00
|
|
|
helper.updateDynamicRam("getOrders", getRamCost(player, "stock", "getOrders"));
|
2021-10-14 09:22:02 +02:00
|
|
|
checkTixApiAccess("getOrders");
|
|
|
|
if (player.bitNodeN !== 8) {
|
|
|
|
if (player.sourceFileLvl(8) <= 2) {
|
|
|
|
throw helper.makeRuntimeErrorMsg(
|
|
|
|
"getOrders",
|
|
|
|
"You must either be in BitNode-8 or have Source-File 8 Level 3.",
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
const orders: any = {};
|
|
|
|
|
|
|
|
const stockMarketOrders = StockMarket["Orders"];
|
2022-01-16 01:45:03 +01:00
|
|
|
for (const symbol of Object.keys(stockMarketOrders)) {
|
2021-10-14 09:22:02 +02:00
|
|
|
const orderBook = stockMarketOrders[symbol];
|
|
|
|
if (orderBook.constructor === Array && orderBook.length > 0) {
|
|
|
|
orders[symbol] = [];
|
|
|
|
for (let i = 0; i < orderBook.length; ++i) {
|
|
|
|
orders[symbol].push({
|
|
|
|
shares: orderBook[i].shares,
|
|
|
|
price: orderBook[i].price,
|
|
|
|
type: orderBook[i].type,
|
|
|
|
position: orderBook[i].pos,
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return orders;
|
|
|
|
},
|
2022-03-17 19:00:22 +01:00
|
|
|
getVolatility: function (_symbol: unknown): number {
|
|
|
|
const symbol = helper.string("getVolatility", "symbol", _symbol);
|
2022-01-05 01:09:34 +01:00
|
|
|
helper.updateDynamicRam("getVolatility", getRamCost(player, "stock", "getVolatility"));
|
2021-10-14 09:22:02 +02:00
|
|
|
if (!player.has4SDataTixApi) {
|
2021-10-27 21:16:16 +02:00
|
|
|
throw helper.makeRuntimeErrorMsg("getVolatility", "You don't have 4S Market Data TIX API Access!");
|
2021-10-14 09:22:02 +02:00
|
|
|
}
|
2021-10-27 21:16:16 +02:00
|
|
|
const stock = getStockFromSymbol(symbol, "getVolatility");
|
2021-10-14 09:22:02 +02:00
|
|
|
|
|
|
|
return stock.mv / 100; // Convert from percentage to decimal
|
|
|
|
},
|
2022-03-17 19:00:22 +01:00
|
|
|
getForecast: function (_symbol: unknown): number {
|
|
|
|
const symbol = helper.string("getForecast", "symbol", _symbol);
|
2022-01-05 01:09:34 +01:00
|
|
|
helper.updateDynamicRam("getForecast", getRamCost(player, "stock", "getForecast"));
|
2021-10-14 09:22:02 +02:00
|
|
|
if (!player.has4SDataTixApi) {
|
2021-10-27 21:16:16 +02:00
|
|
|
throw helper.makeRuntimeErrorMsg("getForecast", "You don't have 4S Market Data TIX API Access!");
|
2021-10-14 09:22:02 +02:00
|
|
|
}
|
2021-10-27 21:16:16 +02:00
|
|
|
const stock = getStockFromSymbol(symbol, "getForecast");
|
2021-10-14 09:22:02 +02:00
|
|
|
|
|
|
|
let forecast = 50;
|
|
|
|
stock.b ? (forecast += stock.otlkMag) : (forecast -= stock.otlkMag);
|
|
|
|
return forecast / 100; // Convert from percentage to decimal
|
|
|
|
},
|
2022-03-17 19:00:22 +01:00
|
|
|
purchase4SMarketData: function (): boolean {
|
2022-01-05 01:09:34 +01:00
|
|
|
helper.updateDynamicRam("purchase4SMarketData", getRamCost(player, "stock", "purchase4SMarketData"));
|
2021-10-14 09:22:02 +02:00
|
|
|
checkTixApiAccess("purchase4SMarketData");
|
|
|
|
|
|
|
|
if (player.has4SData) {
|
2021-11-27 00:43:50 +01:00
|
|
|
workerScript.log("stock.purchase4SMarketData", () => "Already purchased 4S Market Data.");
|
2021-10-14 09:22:02 +02:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2021-11-12 03:35:26 +01:00
|
|
|
if (player.money < getStockMarket4SDataCost()) {
|
2021-11-27 00:43:50 +01:00
|
|
|
workerScript.log("stock.purchase4SMarketData", () => "Not enough money to purchase 4S Market Data.");
|
2021-10-14 09:22:02 +02:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
player.has4SData = true;
|
2021-10-27 20:18:33 +02:00
|
|
|
player.loseMoney(getStockMarket4SDataCost(), "stock");
|
2021-11-27 00:43:50 +01:00
|
|
|
workerScript.log("stock.purchase4SMarketData", () => "Purchased 4S Market Data");
|
2021-10-14 09:22:02 +02:00
|
|
|
return true;
|
|
|
|
},
|
2022-03-17 19:00:22 +01:00
|
|
|
purchase4SMarketDataTixApi: function (): boolean {
|
2022-01-05 01:09:34 +01:00
|
|
|
helper.updateDynamicRam("purchase4SMarketDataTixApi", getRamCost(player, "stock", "purchase4SMarketDataTixApi"));
|
2021-10-14 09:22:02 +02:00
|
|
|
checkTixApiAccess("purchase4SMarketDataTixApi");
|
|
|
|
|
|
|
|
if (player.has4SDataTixApi) {
|
2021-11-27 00:43:50 +01:00
|
|
|
workerScript.log("stock.purchase4SMarketDataTixApi", () => "Already purchased 4S Market Data TIX API");
|
2021-10-14 09:22:02 +02:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2021-11-12 03:35:26 +01:00
|
|
|
if (player.money < getStockMarket4STixApiCost()) {
|
2021-11-27 00:43:50 +01:00
|
|
|
workerScript.log(
|
|
|
|
"stock.purchase4SMarketDataTixApi",
|
|
|
|
() => "Not enough money to purchase 4S Market Data TIX API",
|
|
|
|
);
|
2021-10-14 09:22:02 +02:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
player.has4SDataTixApi = true;
|
2021-10-27 20:18:33 +02:00
|
|
|
player.loseMoney(getStockMarket4STixApiCost(), "stock");
|
2021-11-27 00:43:50 +01:00
|
|
|
workerScript.log("stock.purchase4SMarketDataTixApi", () => "Purchased 4S Market Data TIX API");
|
2021-10-14 09:22:02 +02:00
|
|
|
return true;
|
|
|
|
},
|
2022-03-19 04:58:18 +01:00
|
|
|
purchaseWseAccount: function (): boolean {
|
|
|
|
helper.updateDynamicRam("PurchaseWseAccount", getRamCost(player, "stock", "purchaseWseAccount"));
|
|
|
|
|
|
|
|
if (player.hasWseAccount) {
|
|
|
|
workerScript.log("stock.purchaseWseAccount", () => "Already purchased WSE Account");
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (player.money < getStockMarketWseCost()) {
|
|
|
|
workerScript.log(
|
|
|
|
"stock.purchaseWseAccount",
|
|
|
|
() => "Not enough money to purchase WSE Account Access",
|
|
|
|
);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
player.hasWseAccount = true;
|
|
|
|
player.loseMoney(getStockMarketWseCost(), "stock");
|
|
|
|
workerScript.log("stock.purchaseWseAccount", () => "Purchased WSE Account Access");
|
|
|
|
return true;
|
|
|
|
},
|
|
|
|
purchaseTixApi: function (): boolean {
|
|
|
|
helper.updateDynamicRam("PurchaseTixApi", getRamCost(player, "stock", "purchaseTixApi"));
|
|
|
|
|
|
|
|
if (player.hasTixApiAccess) {
|
|
|
|
workerScript.log("stock.purchaseTixApi", () => "Already purchased TIX API");
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (player.money < getStockMarketTixApiCost()) {
|
|
|
|
workerScript.log(
|
|
|
|
"stock.purchaseTixApi",
|
|
|
|
() => "Not enough money to purchase TIX API Access",
|
|
|
|
);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
player.hasTixApiAccess = true;
|
|
|
|
player.loseMoney(getStockMarketTixApiCost(), "stock");
|
|
|
|
workerScript.log("stock.purchaseTixApi", () => "Purchased TIX API");
|
|
|
|
return true;
|
|
|
|
},
|
2021-10-14 09:22:02 +02:00
|
|
|
};
|
|
|
|
}
|