Skip to content

Commit

Permalink
cents
Browse files Browse the repository at this point in the history
  • Loading branch information
bephrem1 committed Sep 27, 2024
1 parent 3619a3d commit 5c74b8f
Show file tree
Hide file tree
Showing 6 changed files with 63 additions and 75 deletions.
16 changes: 8 additions & 8 deletions src/helpers/test/units.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ describe("units", () => {
// formatted as USD
["$0", 0],
["$1", 100],
["$10", 1000],
["$100", 10_000],
["$10", 10_00],
["$100", 100_00],

["$0.0", 0],
["$0.00", 0],
Expand All @@ -28,27 +28,27 @@ describe("units", () => {
// formatted as numbers
["0", 0],
["1", 100],
["10", 1000],
["100", 10_000],
["10", 10_00],
["100", 100_00],

["1.23", 123],
["1.234", 123.4],

// nested quotes (double)
['"$0"', 0],
['"$1"', 100],
['"$10"', 1000],
['"$10"', 10_00],
['"0"', 0],
['"1"', 100],
['"10"', 1000],
['"10"', 10_00],

// nested quotes (single)
["'$0'", 0],
["'$1'", 100],
["'$10'", 1000],
["'$10'", 10_00],
["'$0'", 0],
["'$1'", 100],
["'$10'", 1000],
["'$10'", 10_00],
];

for (const [input, centsExpected] of inputToExpectedValids) {
Expand Down
40 changes: 18 additions & 22 deletions src/lib/balance.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import {
logLoginMessageAndQuit,
logSessionTokenExpiredAndQuit,
} from "../helpers/errors";
import type { Centicents } from "../helpers/units";
import type { Cents } from "../helpers/units";

const usdFormatter = new Intl.NumberFormat("en-US", {
style: "currency",
Expand All @@ -22,19 +22,19 @@ export function registerBalance(program: Command) {
.option("--json", "Output in JSON format")
.action(async (options) => {
const {
available: { whole: availableWhole, centicents: availableCenticents },
reserved: { whole: reservedWhole, centicents: reservedCenticents },
available: { whole: availableWhole, cents: availableCents },
reserved: { whole: reservedWhole, cents: reservedCents },
} = await getBalance();

if (options.json) {
const jsonOutput = {
available: {
whole: availableWhole,
centicents: availableCenticents,
cents: availableCents,
},
reserved: {
whole: reservedWhole,
centicents: reservedCenticents,
cents: reservedCents,
},
};
console.log(JSON.stringify(jsonOutput, null, 2));
Expand All @@ -43,24 +43,20 @@ export function registerBalance(program: Command) {
const formattedReserved = usdFormatter.format(reservedWhole);

const table = new Table({
head: [
chalk.gray("Type"),
chalk.gray("Amount"),
chalk.gray("Centicents (1/100th of a cent)"),
],
head: [chalk.gray("Type"), chalk.gray("Amount"), chalk.gray("Cents")],
colWidths: [15, 15, 35],
});

table.push(
[
"Available",
chalk.green(formattedAvailable),
chalk.green(availableCenticents.toLocaleString()),
chalk.green(availableCents.toLocaleString()),
],
[
"Reserved",
chalk.gray(formattedReserved),
chalk.gray(reservedCenticents.toLocaleString()),
chalk.gray(reservedCents.toLocaleString()),
],
);

Expand All @@ -71,18 +67,18 @@ export function registerBalance(program: Command) {
});
}

export type BalanceUsdCenticents = {
available: { centicents: Centicents; whole: number };
reserved: { centicents: Centicents; whole: number };
export type BalanceUsdCents = {
available: { cents: Cents; whole: number };
reserved: { cents: Cents; whole: number };
};
export async function getBalance(): Promise<BalanceUsdCenticents> {
export async function getBalance(): Promise<BalanceUsdCents> {
const loggedIn = await isLoggedIn();
if (!loggedIn) {
logLoginMessageAndQuit();

return {
available: { centicents: 0, whole: 0 },
reserved: { centicents: 0, whole: 0 },
available: { cents: 0, whole: 0 },
reserved: { cents: 0, whole: 0 },
};
}
const client = await apiClient();
Expand Down Expand Up @@ -126,12 +122,12 @@ export async function getBalance(): Promise<BalanceUsdCenticents> {

return {
available: {
centicents: available,
whole: available / 10_000,
cents: available,
whole: available / 100,
},
reserved: {
centicents: reserved,
whole: reserved / 10_000,
cents: reserved,
whole: reserved / 100,
},
};
}
1 change: 1 addition & 0 deletions src/lib/buy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,7 @@ async function buyOrderAction(options: SfBuyOptions) {
logAndQuit("Order cancelled");
}
}
console.log(priceCents);

const res = await placeBuyOrder({
instanceType: options.type,
Expand Down
12 changes: 6 additions & 6 deletions src/lib/orders.ts
Original file line number Diff line number Diff line change
Expand Up @@ -138,12 +138,12 @@ function printAsTable(orders: Array<HydratedOrder>) {
order.id,
order.side,
order.instance_type,
usdFormatter.format(order.price / 10000),
usdFormatter.format(order.price / 100),
order.quantity.toString(),
duration,
startDate.toLocaleString(),
status,
executionPrice ? usdFormatter.format(executionPrice / 10000) : "-",
executionPrice ? usdFormatter.format(executionPrice / 100) : "-",
]);
}
}
Expand All @@ -161,8 +161,8 @@ export function registerOrders(program: Command) {
.option("--side <side>", "Filter by order side (buy or sell)")
.option("-t, --type <type>", "Filter by instance type")
.option("--public", "Include public orders")
.option("--min-price <price>", "Filter by minimum price (in Centicents)")
.option("--max-price <price>", "Filter by maximum price (in Centicents)")
.option("--min-price <price>", "Filter by minimum price (in cents)")
.option("--max-price <price>", "Filter by maximum price (in cents)")
.option(
"--min-start <date>",
"Filter by minimum start date (ISO 8601 datestring)",
Expand Down Expand Up @@ -198,11 +198,11 @@ export function registerOrders(program: Command) {
)
.option(
"--min-fill-price <price>",
"Filter by minimum fill price (in Centicents)",
"Filter by minimum fill price (in cents)",
)
.option(
"--max-fill-price <price>",
"Filter by maximum fill price (in Centicents)",
"Filter by maximum fill price (in cents)",
)
.option("--exclude-cancelled", "Exclude cancelled orders")
.option("--only-cancelled", "Show only cancelled orders")
Expand Down
14 changes: 6 additions & 8 deletions src/lib/sell.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,15 @@ import {
logSessionTokenExpiredAndQuit,
} from "../helpers/errors";
import { getContract } from "../helpers/fetchers";
import { pricePerGPUHourToTotalPrice } from "../helpers/price";
import {
priceWholeToCenticents,
priceWholeToCents,
roundEndDate,
roundStartDate,
} from "../helpers/units";
import { waitForOrderToNotBePending } from "../helpers/waitingForOrder";
import { GPUS_PER_NODE } from "./constants";
import type { PlaceSellOrderParameters } from "./orders";
import { pricePerGPUHourToTotalPriceCents } from "../helpers/price";

export function registerSell(program: Command) {
program
Expand Down Expand Up @@ -72,10 +72,8 @@ async function placeSellOrder(options: {
return logLoginMessageAndQuit();
}

const { centicents: priceCenticents, invalid } = priceWholeToCenticents(
options.price,
);
if (invalid || !priceCenticents) {
const { cents: priceCents, invalid } = priceWholeToCents(options.price);
if (invalid || !priceCents) {
return logAndQuit(`Invalid price: ${options.price}`);
}

Expand Down Expand Up @@ -131,8 +129,8 @@ async function placeSellOrder(options: {
const totalDurationSecs = dayjs(endDate).diff(startDate, "s");
const nodes = Math.ceil(options.accelerators / GPUS_PER_NODE);

const totalPrice = pricePerGPUHourToTotalPrice(
priceCenticents,
const totalPrice = pricePerGPUHourToTotalPriceCents(
priceCents,
totalDurationSecs,
nodes,
GPUS_PER_NODE,
Expand Down
55 changes: 24 additions & 31 deletions src/lib/updown.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@ import type { Command } from "commander";
import parseDuration from "parse-duration";
import { apiClient } from "../apiClient";
import { logAndQuit } from "../helpers/errors";
import { centicentsToDollarsFormatted } from "../helpers/units";
import { getBalance } from "./balance";
import { getQuote } from "./buy";
import { formatDuration } from "./orders";
import { centsToDollarsFormatted, type Cents } from "../helpers/units";

export function registerUp(program: Command) {
const cmd = program
Expand Down Expand Up @@ -41,7 +41,7 @@ export function registerDown(program: Command) {
});
}

const DEFAULT_PRICE_PER_NODE_HOUR_IN_CENTICENTS = 2.65 * 8 * 10_000;
const DEFAULT_PRICE_PER_NODE_HOUR_IN_CENTS = 2.65 * 8 * 100;

async function getDefaultProcurementOptions(props: {
duration?: string;
Expand Down Expand Up @@ -69,7 +69,7 @@ async function getDefaultProcurementOptions(props: {
});

// Eventually we should replace this price with yesterday's index price
let quotePrice = DEFAULT_PRICE_PER_NODE_HOUR_IN_CENTICENTS;
let quotePrice = DEFAULT_PRICE_PER_NODE_HOUR_IN_CENTS;
if (quote) {
// per hour price
quotePrice = quote.price / durationHours;
Expand All @@ -78,29 +78,27 @@ async function getDefaultProcurementOptions(props: {
const pricePerNodeHourInDollars = props.pricePerNodeHour
? Number.parseInt(props.pricePerNodeHour)
: quotePrice;
const pricePerNodeHourInCenticents = Math.ceil(pricePerNodeHourInDollars);
const pricePerNodeHourInCents = Math.ceil(pricePerNodeHourInDollars * 100);

const totalPriceInCenticents =
pricePerNodeHourInCenticents *
Number.parseInt(props.n ?? "1") *
durationHours;
const totalPriceInCents =
pricePerNodeHourInCents * Number.parseInt(props.n ?? "1") * durationHours;

return {
durationHours,
pricePerNodeHourInCenticents,
pricePerNodeHourInCents,
n,
type,
totalPriceInCenticents,
totalPriceInCents,
};
}

// Instruct the user to set a price that's lower
function getSuggestedCommandWhenBalanceLow(props: {
durationHours: number;
pricePerNodeHourInCenticents: number;
pricePerNodeHourInCents: Cents;
n: number;
totalPriceInCenticents: number;
balance: number;
totalPriceInCents: Cents;
balance: Cents;
}) {
const affordablePrice = props.balance / 100 / (props.n * props.durationHours);

Expand All @@ -110,9 +108,9 @@ function getSuggestedCommandWhenBalanceLow(props: {

function confirmPlaceOrderMessage(options: {
durationHours: number;
pricePerNodeHourInCenticents: number;
pricePerNodeHourInCents: number;
n: number;
totalPriceInCenticents: number;
totalPriceInCents: number;
type: string;
}) {
const totalNodesLabel = c.green(options.n);
Expand All @@ -125,7 +123,7 @@ function confirmPlaceOrderMessage(options: {
const topLine = `Turning on ${totalNodesLabel} ${instanceTypeLabel} ${nodesLabel} continuously for ${c.green(formatDuration(durationInMilliseconds))} ${timeDescription}`;

const dollarsLabel = c.green(
centicentsToDollarsFormatted(options.pricePerNodeHourInCenticents),
centsToDollarsFormatted(options.pricePerNodeHourInCents),
);

const priceLine = `\n Pay ${dollarsLabel} per node hour?`;
Expand All @@ -142,13 +140,8 @@ async function up(props: {
}) {
const client = await apiClient();

const {
durationHours,
n,
type,
pricePerNodeHourInCenticents,
totalPriceInCenticents,
} = await getDefaultProcurementOptions(props);
const { durationHours, n, type, pricePerNodeHourInCents, totalPriceInCents } =
await getDefaultProcurementOptions(props);

if (durationHours && durationHours < 1) {
console.error("Minimum duration is 1 hour");
Expand All @@ -158,9 +151,9 @@ async function up(props: {
if (!props.y) {
const confirmationMessage = confirmPlaceOrderMessage({
durationHours,
pricePerNodeHourInCenticents,
pricePerNodeHourInCents,
n,
totalPriceInCenticents,
totalPriceInCents,
type,
});
const confirmed = await confirm({
Expand All @@ -175,15 +168,15 @@ async function up(props: {

const balance = await getBalance();

if (balance.available.centicents < totalPriceInCenticents) {
if (balance.available.cents < totalPriceInCents) {
console.log(
`You can't afford this. Available balance: $${(balance.available.centicents / 1000000).toFixed(2)}, Minimum price: $${(totalPriceInCenticents / 1000000).toFixed(2)}\n`,
`You can't afford this. Available balance: $${(balance.available.cents / 100).toFixed(2)}, Minimum price: $${(totalPriceInCents / 100).toFixed(2)}\n`,
);
const cmd = getSuggestedCommandWhenBalanceLow({
durationHours,
pricePerNodeHourInCenticents,
pricePerNodeHourInCents,
n,
totalPriceInCenticents,
totalPriceInCents,
balance: balance.available.whole,
});
console.log(cmd);
Expand Down Expand Up @@ -213,7 +206,7 @@ async function up(props: {
// we only update the duration & price if it's set
min_duration_in_hours: props.duration ? durationHours : undefined,
max_price_per_node_hour: props.price
? pricePerNodeHourInCenticents
? pricePerNodeHourInCents
: undefined,
},
});
Expand All @@ -225,7 +218,7 @@ async function up(props: {
body: {
instance_type: type,
quantity: n,
max_price_per_node_hour: pricePerNodeHourInCenticents,
max_price_per_node_hour: pricePerNodeHourInCents,
min_duration_in_hours: Math.max(durationHours, 1),
},
});
Expand Down

0 comments on commit 5c74b8f

Please sign in to comment.