STOCKMARKET: Move and Reorganize Constants (#688)

This commit is contained in:
Caldwell 2023-08-01 04:12:49 +02:00 committed by GitHub
parent e9bbe57902
commit a85efbc4da
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 49 additions and 53 deletions

@ -31,11 +31,6 @@ export const CONSTANTS: {
PurchasedServerMaxRam: number;
MultipleAugMultiplier: number;
TorRouterCost: number;
WSEAccountCost: number;
TIXAPICost: number;
MarketData4SCost: number;
MarketDataTixApi4SCost: number;
StockMarketCommission: number;
HospitalCostPerHp: number;
IntelligenceCrimeWeight: number;
IntelligenceInfiltrationWeight: number;
@ -140,13 +135,6 @@ export const CONSTANTS: {
// TOR Router
TorRouterCost: 200e3,
// Stock market
WSEAccountCost: 200e6,
TIXAPICost: 5e9,
MarketData4SCost: 1e9,
MarketDataTixApi4SCost: 25e9,
StockMarketCommission: 100e3,
// Hospital/Health
HospitalCostPerHp: 100e3,

@ -11,7 +11,7 @@ import {
import { PositionType } from "@enums";
import { CONSTANTS } from "../Constants";
import { StockMarketConstants } from "./data/Constants";
import { Player } from "@player";
import { formatMoney, formatShares } from "../ui/formatNumber";
@ -103,7 +103,7 @@ export function buyStock(
const origTotal = stock.playerShares * stock.playerAvgPx;
Player.loseMoney(totalPrice, "stock");
const newTotal = origTotal + totalPrice - CONSTANTS.StockMarketCommission;
const newTotal = origTotal + totalPrice - StockMarketConstants.StockMarketCommission;
stock.playerShares = Math.round(stock.playerShares + shares);
stock.playerAvgPx = newTotal / stock.playerShares;
processTransactionForecastMovement(stock, shares);
@ -114,13 +114,13 @@ export function buyStock(
if (ctx) {
const resultTxt = `Bought ${formatShares(shares)} shares of ${stock.symbol} for ${formatMoney(
totalPrice,
)}. Paid ${formatMoney(CONSTANTS.StockMarketCommission)} in commission fees.`;
)}. Paid ${formatMoney(StockMarketConstants.StockMarketCommission)} in commission fees.`;
helpers.log(ctx, () => resultTxt);
} else if (opts.suppressDialog !== true) {
dialogBoxCreate(
<>
Bought {formatShares(shares)} shares of {stock.symbol} for <Money money={totalPrice} />. Paid{" "}
<Money money={CONSTANTS.StockMarketCommission} /> in commission fees.
<Money money={StockMarketConstants.StockMarketCommission} /> in commission fees.
</>,
);
}
@ -278,7 +278,7 @@ export function shortStock(
const origTotal = stock.playerShortShares * stock.playerAvgShortPx;
Player.loseMoney(totalPrice, "stock");
const newTotal = origTotal + totalPrice - CONSTANTS.StockMarketCommission;
const newTotal = origTotal + totalPrice - StockMarketConstants.StockMarketCommission;
stock.playerShortShares = Math.round(stock.playerShortShares + shares);
stock.playerAvgShortPx = newTotal / stock.playerShortShares;
processTransactionForecastMovement(stock, shares);
@ -290,14 +290,14 @@ export function shortStock(
if (ctx) {
const resultTxt =
`Bought a short position of ${formatShares(shares)} shares of ${stock.symbol} ` +
`for ${formatMoney(totalPrice)}. Paid ${formatMoney(CONSTANTS.StockMarketCommission)} ` +
`for ${formatMoney(totalPrice)}. Paid ${formatMoney(StockMarketConstants.StockMarketCommission)} ` +
`in commission fees.`;
helpers.log(ctx, () => resultTxt);
} else if (!opts.suppressDialog) {
dialogBoxCreate(
<>
Bought a short position of {formatShares(shares)} shares of {stock.symbol} for <Money money={totalPrice} />.
Paid <Money money={CONSTANTS.StockMarketCommission} /> in commission fees.
Paid <Money money={StockMarketConstants.StockMarketCommission} /> in commission fees.
</>,
);
}

@ -1,9 +1,9 @@
import type { IOrderBook } from "./IOrderBook";
import type { IStockMarket } from "./IStockMarket";
import { Order } from "./Order";
import { StockMarketConstants } from "./data/Constants";
import { processOrders } from "./OrderProcessing";
import { Stock } from "./Stock";
import { TicksPerCycle } from "./StockMarketConstants";
import { InitStockMetadata } from "./data/InitStockMetadata";
import { PositionType, OrderType, StockSymbol } from "@enums";
@ -165,7 +165,7 @@ export function initStockMarket(): void {
StockMarket.storedCycles = 0;
StockMarket.lastUpdate = 0;
StockMarket.ticksUntilCycle = TicksPerCycle;
StockMarket.ticksUntilCycle = StockMarketConstants.TicksPerCycle;
initSymbolToStockMap();
}
@ -191,13 +191,11 @@ function stockMarketCycle(): void {
stock.flipForecastForecast();
}
StockMarket.ticksUntilCycle = TicksPerCycle;
StockMarket.ticksUntilCycle = StockMarketConstants.TicksPerCycle;
}
}
// Stock prices updated every 6 seconds
const msPerStockUpdate = 6e3;
const cyclesPerStockUpdate = msPerStockUpdate / CONSTANTS.MilliPerCycle;
const cyclesPerStockUpdate = StockMarketConstants.msPerStockUpdate / CONSTANTS.MilliPerCycle;
export function processStockPrices(numCycles = 1): void {
if (StockMarket.storedCycles == null || isNaN(StockMarket.storedCycles)) {
StockMarket.storedCycles = 0;
@ -211,14 +209,14 @@ export function processStockPrices(numCycles = 1): void {
// We can process the update every 4 seconds as long as there are enough
// stored cycles. This lets us account for offline time
const timeNow = new Date().getTime();
if (timeNow - StockMarket.lastUpdate < 4e3) return;
if (timeNow - StockMarket.lastUpdate < StockMarketConstants.msPerStockUpdateMin) return;
StockMarket.lastUpdate = timeNow;
StockMarket.storedCycles -= cyclesPerStockUpdate;
// Cycle
if (StockMarket.ticksUntilCycle == null || typeof StockMarket.ticksUntilCycle !== "number") {
StockMarket.ticksUntilCycle = TicksPerCycle;
StockMarket.ticksUntilCycle = StockMarketConstants.TicksPerCycle;
}
--StockMarket.ticksUntilCycle;
if (StockMarket.ticksUntilCycle <= 0) stockMarketCycle();

@ -1,5 +0,0 @@
/**
* How many stock market 'ticks' before a 'cycle' is triggered.
* A 'tick' is whenever stock prices update
*/
export const TicksPerCycle = 75;

@ -1,18 +1,18 @@
import { currentNodeMults } from "../BitNode/BitNodeMultipliers";
import { CONSTANTS } from "../Constants";
import { StockMarketConstants } from "./data/Constants";
export function getStockMarket4SDataCost(): number {
return CONSTANTS.MarketData4SCost * currentNodeMults.FourSigmaMarketDataCost;
return StockMarketConstants.MarketData4SCost * currentNodeMults.FourSigmaMarketDataCost;
}
export function getStockMarket4STixApiCost(): number {
return CONSTANTS.MarketDataTixApi4SCost * currentNodeMults.FourSigmaMarketDataApiCost;
return StockMarketConstants.MarketDataTixApi4SCost * currentNodeMults.FourSigmaMarketDataApiCost;
}
export function getStockMarketWseCost(): number {
return CONSTANTS.WSEAccountCost;
return StockMarketConstants.WSEAccountCost;
}
export function getStockMarketTixApiCost(): number {
return CONSTANTS.TIXAPICost;
return StockMarketConstants.TIXAPICost;
}

@ -1,6 +1,6 @@
import { Stock } from "./Stock";
import { PositionType } from "@enums";
import { CONSTANTS } from "../Constants";
import { StockMarketConstants } from "./data/Constants";
// Amount by which a stock's forecast changes during each price movement
export const forecastChangePerPriceMovement = 0.006;
@ -25,9 +25,9 @@ export function getBuyTransactionCost(stock: Stock, shares: number, posType: Pos
// If the number of shares doesn't trigger a price movement, its a simple calculation
if (isLong) {
return shares * stock.getAskPrice() + CONSTANTS.StockMarketCommission;
return shares * stock.getAskPrice() + StockMarketConstants.StockMarketCommission;
} else {
return shares * stock.getBidPrice() + CONSTANTS.StockMarketCommission;
return shares * stock.getBidPrice() + StockMarketConstants.StockMarketCommission;
}
}
@ -50,11 +50,11 @@ export function getSellTransactionGain(stock: Stock, shares: number, posType: Po
const isLong = posType === PositionType.Long;
if (isLong) {
return shares * stock.getBidPrice() - CONSTANTS.StockMarketCommission;
return shares * stock.getBidPrice() - StockMarketConstants.StockMarketCommission;
} else {
// Calculating gains for a short position requires calculating the profit made
const origCost = shares * stock.playerAvgShortPx;
const profit = (stock.playerAvgShortPx - stock.getAskPrice()) * shares - CONSTANTS.StockMarketCommission;
const profit = (stock.playerAvgShortPx - stock.getAskPrice()) * shares - StockMarketConstants.StockMarketCommission;
return origCost + profit;
}
@ -124,7 +124,7 @@ export function calculateBuyMaxAmount(stock: Stock, posType: PositionType, money
const isLong = posType === PositionType.Long;
const remainingMoney = money - CONSTANTS.StockMarketCommission;
const remainingMoney = money - StockMarketConstants.StockMarketCommission;
const currPrice = isLong ? stock.getAskPrice() : stock.getBidPrice();
return Math.floor(remainingMoney / currPrice);

@ -0,0 +1,15 @@
export const StockMarketConstants = {
//stock tick times in milliseconds
msPerStockUpdate: 6e3,
msPerStockUpdateMin: 4e3,
//defines the length of the flip timer in stock cycles
TicksPerCycle: 75,
// Stockmarket costs Constants
WSEAccountCost: 200e6,
TIXAPICost: 5e9,
MarketData4SCost: 1e9,
MarketDataTixApi4SCost: 25e9,
StockMarketCommission: 100e3,
};

@ -7,7 +7,7 @@ import React, { useState } from "react";
import { getStockMarket4SDataCost, getStockMarket4STixApiCost } from "../StockMarketCosts";
import { CONSTANTS } from "../../Constants";
import { StockMarketConstants } from "../data/Constants";
import { Player } from "@player";
import { Money } from "../../ui/React/Money";
import { initStockMarket } from "../StockMarket";
@ -83,16 +83,16 @@ function PurchaseWseAccountButton(props: IProps): React.ReactElement {
if (Player.hasWseAccount) {
return;
}
if (!Player.canAfford(CONSTANTS.WSEAccountCost)) {
if (!Player.canAfford(StockMarketConstants.WSEAccountCost)) {
return;
}
Player.hasWseAccount = true;
initStockMarket();
Player.loseMoney(CONSTANTS.WSEAccountCost, "stock");
Player.loseMoney(StockMarketConstants.WSEAccountCost, "stock");
props.rerender();
}
const cost = CONSTANTS.WSEAccountCost;
const cost = StockMarketConstants.WSEAccountCost;
return (
<>
<Typography>To begin trading, you must first purchase an account:</Typography>
@ -109,11 +109,11 @@ function PurchaseTixApiAccessButton(props: IProps): React.ReactElement {
if (Player.hasTixApiAccess) {
return;
}
if (!Player.canAfford(CONSTANTS.TIXAPICost)) {
if (!Player.canAfford(StockMarketConstants.TIXAPICost)) {
return;
}
Player.hasTixApiAccess = true;
Player.loseMoney(CONSTANTS.TIXAPICost, "stock");
Player.loseMoney(StockMarketConstants.TIXAPICost, "stock");
props.rerender();
}
@ -124,7 +124,7 @@ function PurchaseTixApiAccessButton(props: IProps): React.ReactElement {
</Typography>
);
} else {
const cost = CONSTANTS.TIXAPICost;
const cost = StockMarketConstants.TIXAPICost;
return (
<Button disabled={!Player.canAfford(cost) || !Player.hasWseAccount} onClick={purchaseTixApiAccess}>
Buy Trade Information eXchange (TIX) API Access -&nbsp;
@ -203,7 +203,7 @@ export function InfoAndPurchases(props: IProps): React.ReactElement {
<Purchase4SMarketDataButton {...props} />
<Typography>
Commission Fees: Every transaction you make has a{" "}
<Money money={CONSTANTS.StockMarketCommission} forPurchase={true} /> commission fee.
<Money money={StockMarketConstants.StockMarketCommission} forPurchase={true} /> commission fee.
</Typography>
<br />
<Typography>

@ -1,4 +1,4 @@
import { CONSTANTS } from "../../src/Constants";
import { StockMarketConstants } from "../../src/StockMarket/data/Constants";
import { Player } from "../../src/Player";
import { Company } from "../../src/Company/Company";
@ -42,7 +42,7 @@ jest.mock(`!!raw-loader!../NetscriptDefinitions.d.ts`, () => "", {
// }));
describe("Stock Market Tests", function () {
const commission = CONSTANTS.StockMarketCommission;
const commission = StockMarketConstants.StockMarketCommission;
// Generic Stock object that can be used by each test
let stock: Stock;