diff --git a/src/helpers/units.ts b/src/helpers/units.ts index 22d408e..30f13d6 100644 --- a/src/helpers/units.ts +++ b/src/helpers/units.ts @@ -1,3 +1,4 @@ +import dayjs from "dayjs"; import type { Nullable } from "../types/empty"; // -- time @@ -25,6 +26,16 @@ export function roundStartDate(startDate: Date): Date { } } +export function computeApproximateDurationSeconds( + startDate: Date | "NOW", + endDate: Date, +): number { + const startEpoch = + startDate === "NOW" ? currentEpoch() : dateToEpoch(startDate); + const endEpoch = dateToEpoch(endDate); + return dayjs(epochToDate(endEpoch)).diff(dayjs(epochToDate(startEpoch)), "s"); +} + export function roundEndDate(endDate: Date): Date { return epochToDate(roundEpochUpToHour(dateToEpoch(endDate))); } diff --git a/src/lib/buy.ts b/src/lib/buy.ts index 796e36e..3bed040 100644 --- a/src/lib/buy.ts +++ b/src/lib/buy.ts @@ -20,6 +20,7 @@ import { import { type Cents, centsToDollarsFormatted, + computeApproximateDurationSeconds, priceWholeToCents, roundEndDate, roundStartDate, @@ -50,7 +51,10 @@ export function registerBuy(program: Command) { .option("-n, --accelerators ", "Specify the number of GPUs", "8") .requiredOption("-d, --duration ", "Specify the duration", "1h") .option("-p, --price ", "The price in dollars, per GPU hour") - .option("-s, --start ", "Specify the start date") + .option( + "-s, --start ", + "Specify the start date. Can be a date, relative time like '+1d', or the string 'NOW'", + ) .option("-y, --yes", "Automatically confirm the order") .option("--quote", "Only provide a quote for the order") .action(buyOrderAction); @@ -109,11 +113,26 @@ async function buyOrderAction(options: SfBuyOptions) { const confirmWithUser = yesFlagOmitted || !options.yes; // parse starts at - let startDate = options.start ? chrono.parseDate(options.start) : new Date(); - if (!startDate) { - return logAndQuit("Invalid start date"); + let startDate: Date | "NOW"; + switch (options.start) { + case null: + case undefined: + case "NOW": + startDate = "NOW"; + break; + default: { + const parsed = chrono.parseDate(options.start); + if (!parsed) { + return logAndQuit("Invalid start date"); + } + startDate = parsed; + } } + let endDate: Date = dayjs(startDate === "NOW" ? new Date() : startDate) + .add(durationSeconds, "s") + .toDate(); + let didQuote = false; if (options.quote) { const quote = await getQuote({ instanceType: options.type, @@ -126,6 +145,10 @@ async function buyOrderAction(options: SfBuyOptions) { return logAndQuit("Not enough data exists to quote this order."); } + startDate = quote.start_at === "NOW" ? "NOW" : new Date(quote.start_at); + endDate = new Date(quote.end_at); + durationSeconds = computeApproximateDurationSeconds(startDate, endDate); + const priceLabelUsd = c.green(centsToDollarsFormatted(quote.price)); const priceLabelPerGPUHour = c.green( centsToDollarsFormatted( @@ -139,110 +162,130 @@ async function buyOrderAction(options: SfBuyOptions) { ); console.log( - `This order is projected to cost ${priceLabelUsd} total or ${priceLabelPerGPUHour} per GPU hour`, + `Found availability from ${c.green(quote.start_at)} to ${c.green(quote.end_at)} (${c.green(formatDuration(durationSeconds * 1000))}) at ${priceLabelUsd} total (${priceLabelPerGPUHour}/GPU-hour)`, ); - } else { - // quote if no price was provided - if (!priceCents) { - const quote = await getQuote({ - instanceType: options.type, - quantity: quantity, - startsAt: startDate, - durationSeconds, - }); - - if (!quote) { - const durationInHours = durationSeconds / 3600; + didQuote = true; + } else if (!priceCents) { + const quote = await getQuote({ + instanceType: options.type, + quantity: quantity, + startsAt: startDate, + durationSeconds, + }); - console.log(`No one is selling this right now. To ask someone to sell it to you, add a price you're willing to pay. For example: + if (!quote) { + const durationInHours = durationSeconds / 3600; - sf buy -d "${durationInHours}h" -n ${quantity * GPUS_PER_NODE} -p "2.50" - `); + console.log(`No one is selling this right now. To ask someone to sell it to you, add a price you're willing to pay. For example: - return process.exit(1); - } + sf buy -d "${durationInHours}h" -n ${quantity * GPUS_PER_NODE} -p "2.50" + `); - priceCents = quote.price; - durationSeconds = quote.duration; - startDate = new Date(quote.start_at); + return process.exit(1); } - if (!durationSeconds) { - throw new Error("unexpectly no duration provided"); - } - if (!priceCents) { - throw new Error("unexpectly no price provided"); - } + startDate = quote.start_at === "NOW" ? "NOW" : new Date(quote.start_at); + endDate = new Date(quote.end_at); + durationSeconds = computeApproximateDurationSeconds(startDate, endDate); + priceCents = quote.price; + didQuote = true; + } - // round the start and end dates. If we came from a quote, they should already be rounded, - // however, there may have been a delay between the quote and now, so we may need to move the start time up to the next minute - startDate = roundStartDate(startDate); - let endDate = dayjs(startDate).add(durationSeconds, "s").toDate(); - endDate = roundEndDate(endDate); - - if (confirmWithUser) { - const confirmationMessage = confirmPlaceOrderMessage({ - instanceType: options.type, - priceCents, - quantity, - startsAt: startDate, - endsAt: endDate, - confirmWithUser, - quoteOnly: isQuoteOnly, - }); - const confirmed = await confirm({ - message: confirmationMessage, - default: false, - }); - - if (!confirmed) { - logAndQuit("Order cancelled"); - } - } + if (!durationSeconds) { + throw new Error("unexpectly no duration provided"); + } + if (!priceCents) { + throw new Error("unexpectly no price provided"); + } + + // if we didn't quote, we need to round the start and end dates + if (!didQuote) { + // round the start date if it's not "NOW". + const roundedStartDate = + startDate !== "NOW" ? roundStartDate(startDate) : startDate; - const res = await placeBuyOrder({ + // round the end date. + const roundedEndDate = roundEndDate(endDate); + + // if we rounded the time, prorate the price + const roundedDurationSeconds = computeApproximateDurationSeconds( + roundedStartDate, + roundedEndDate, + ); + + const priceCentsPerSecond = priceCents / durationSeconds; + const roundedPriceCents = priceCentsPerSecond * roundedDurationSeconds; + + priceCents = roundedPriceCents; + startDate = roundedStartDate; + endDate = roundedEndDate; + durationSeconds = roundedDurationSeconds; + } + + if (confirmWithUser) { + const confirmationMessage = confirmPlaceOrderMessage({ instanceType: options.type, priceCents, quantity, - // round start date again because the user might have taken a long time to confirm - // most of the time this will do nothing, but when it does it will move the start date forwrd one minute - startsAt: roundStartDate(startDate), + durationSeconds, + startsAt: startDate, endsAt: endDate, confirmWithUser, quoteOnly: isQuoteOnly, }); + const confirmed = await confirm({ + message: confirmationMessage, + default: false, + }); - const order = await waitForOrderToNotBePending(res.id); - if (!order) { - return; + if (!confirmed) { + logAndQuit("Order cancelled"); } + } + + const res = await placeBuyOrder({ + instanceType: options.type, + priceCents, + quantity, + // round start date again because the user might have taken a long time to confirm + // most of the time this will do nothing, but when it does it will move the start date forwrd one minute + startsAt: startDate === "NOW" ? "NOW" : roundStartDate(startDate), + endsAt: endDate, + confirmWithUser, + quoteOnly: isQuoteOnly, + }); + + const order = await waitForOrderToNotBePending(res.id); + if (!order) { + return; + } - if (order.status === "filled") { - const now = new Date(); - const startAt = new Date(order.start_at); - const timeDiff = startAt.getTime() - now.getTime(); - const oneMinuteInMs = 60 * 1000; + if (order.status === "filled") { + const now = new Date(); + const startAt = new Date(order.start_at); + const timeDiff = startAt.getTime() - now.getTime(); + const oneMinuteInMs = 60 * 1000; - if (now >= startAt || timeDiff <= oneMinuteInMs) { - console.log(`Your nodes are currently spinning up. Once they're online, you can view them using: + if (now >= startAt || timeDiff <= oneMinuteInMs) { + console.log(`Your nodes are currently spinning up. Once they're online, you can view them using: sf instances ls `); - } else { - const contractStartTime = dayjs(startAt); - const timeFromNow = contractStartTime.fromNow(); - console.log(`Your contract begins ${c.green(timeFromNow)}. You can view more details using: + } else { + const contractStartTime = dayjs(startAt); + const timeFromNow = contractStartTime.fromNow(); + console.log(`Your contract begins ${c.green(timeFromNow)}. You can view more details using: sf contracts ls `); - } - return; } + return; + } - if (order.status === "open") { - console.log(`Your order wasn't accepted yet. You can check it's status with: + if (order.status === "open") { + console.log(`Your order wasn't accepted yet. You can check it's status with: sf orders ls @@ -251,15 +294,14 @@ async function buyOrderAction(options: SfBuyOptions) { sf orders cancel ${order.id} `); - return; - } + return; + } - console.error(`Order likely did not execute. Check the status with: + console.error(`Order likely did not execute. Check the status with: sf orders ls `); - } } function confirmPlaceOrderMessage(options: BuyOptions) { @@ -271,13 +313,13 @@ function confirmPlaceOrderMessage(options: BuyOptions) { const instanceTypeLabel = c.green(options.instanceType); const nodesLabel = options.quantity > 1 ? "nodes" : "node"; - const durationHumanReadable = formatDuration( - options.endsAt.getTime() - options.startsAt.getTime(), - ); + const durationHumanReadable = formatDuration(options.durationSeconds * 1000); const endsAtLabel = c.green( dayjs(options.endsAt).format("MM/DD/YYYY hh:mm A"), ); - const fromNowTime = dayjs(options.startsAt).fromNow(); + const fromNowTime = dayjs( + options.startsAt === "NOW" ? new Date() : options.startsAt, + ).fromNow(); let timeDescription: string; if ( @@ -287,23 +329,23 @@ function confirmPlaceOrderMessage(options: BuyOptions) { timeDescription = `from ${c.green("now")} until ${endsAtLabel}`; } else { const startAtLabel = c.green( - dayjs(options.startsAt).format("MM/DD/YYYY hh:mm A"), + options.startsAt === "NOW" + ? "NOW" + : dayjs(options.startsAt).format("MM/DD/YYYY hh:mm A"), ); timeDescription = `from ${startAtLabel} (${c.green(fromNowTime)}) until ${endsAtLabel}`; } - const durationInSeconds = Math.ceil( - (options.endsAt.getTime() - options.startsAt.getTime()) / 1000, - ); const pricePerGPUHour = totalPriceToPricePerGPUHour( options.priceCents, - durationInSeconds, + options.durationSeconds, options.quantity, GPUS_PER_NODE, ); const pricePerHourLabel = c.green(centsToDollarsFormatted(pricePerGPUHour)); + const totalPriceLabel = c.green(centsToDollarsFormatted(options.priceCents)); - const topLine = `${totalNodesLabel} ${instanceTypeLabel} ${nodesLabel} (${GPUS_PER_NODE * options.quantity} GPUs) at ${pricePerHourLabel} per GPU hour for ${c.green(durationHumanReadable)} ${timeDescription}`; + const topLine = `${totalNodesLabel} ${instanceTypeLabel} ${nodesLabel} (${GPUS_PER_NODE * options.quantity} GPUs) at ${pricePerHourLabel} per GPU hour for ${c.green(durationHumanReadable)} ${timeDescription} for a total of ${totalPriceLabel}`; const dollarsLabel = c.green(centsToDollarsFormatted(pricePerGPUHour)); @@ -318,12 +360,15 @@ type BuyOptions = { instanceType: string; priceCents: number; quantity: number; - startsAt: Date; + startsAt: Date | "NOW"; endsAt: Date; + durationSeconds: number; confirmWithUser: boolean; quoteOnly: boolean; }; -export async function placeBuyOrder(options: BuyOptions) { +export async function placeBuyOrder( + options: Omit, +) { const api = await apiClient(); const { data, error, response } = await api.POST("/v0/orders", { body: { @@ -331,7 +376,10 @@ export async function placeBuyOrder(options: BuyOptions) { instance_type: options.instanceType, quantity: options.quantity, // round start date again because the user might take a long time to confirm - start_at: roundStartDate(options.startsAt).toISOString(), + start_at: + options.startsAt === "NOW" + ? "NOW" + : roundStartDate(options.startsAt).toISOString(), end_at: options.endsAt.toISOString(), price: options.priceCents, }, @@ -362,7 +410,7 @@ export async function placeBuyOrder(options: BuyOptions) { type QuoteOptions = { instanceType: string; quantity: number; - startsAt: Date; + startsAt: Date | "NOW"; durationSeconds: number; }; export async function getQuote(options: QuoteOptions) { @@ -375,8 +423,10 @@ export async function getQuote(options: QuoteOptions) { instance_type: options.instanceType, quantity: options.quantity, duration: options.durationSeconds, - min_start_date: options.startsAt.toISOString(), - max_start_date: options.startsAt.toISOString(), + min_start_date: + options.startsAt === "NOW" ? "NOW" : options.startsAt.toISOString(), + max_start_date: + options.startsAt === "NOW" ? "NOW" : options.startsAt.toISOString(), }, }, }); diff --git a/src/schema.ts b/src/schema.ts index 8a1489b..accc37c 100644 --- a/src/schema.ts +++ b/src/schema.ts @@ -68,6 +68,22 @@ export interface paths { patch?: never; trace?: never; }; + "/v0/orders/cancel-all": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + post: operations["postV0OrdersCancel-all"]; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; "/v0/instances": { parameters: { query?: never; @@ -210,9 +226,9 @@ export type $defs = Record; export interface operations { getV0Prices: { parameters: { - query: { + query?: { /** @description The instance type. */ - instance_type: string; + instance_type?: string; /** @description The minimum quantity of nodes filled blocks included in the price calculation contain. */ min_quantity?: number; /** @description The maximum quantity of nodes filled blocks included in the price calculation contain. */ @@ -240,11 +256,11 @@ export interface operations { /** @constant */ object: "price-history-item"; gpu_hour?: { - /** @description The minimum price per GPU hour for the period (in centicents, 1/100th of a cent). */ + /** @description The minimum price per GPU hour for the period (in cents, 1 = $0.01). */ min: number; - /** @description The maximum price per GPU hour for the period (in centicents, 1/100th of a cent). */ + /** @description The maximum price per GPU hour for the period (in cents, 1 = $0.01). */ max: number; - /** @description The average price per GPU hour for the period (in centicents, 1/100th of a cent). */ + /** @description The average price per GPU hour for the period (in cents, 1 = $0.01). */ avg: number; }; /** @description ISO 8601 datetime marking the start of the period. */ @@ -263,11 +279,11 @@ export interface operations { /** @constant */ object: "price-history-item"; gpu_hour?: { - /** @description The minimum price per GPU hour for the period (in centicents, 1/100th of a cent). */ + /** @description The minimum price per GPU hour for the period (in cents, 1 = $0.01). */ min: number; - /** @description The maximum price per GPU hour for the period (in centicents, 1/100th of a cent). */ + /** @description The maximum price per GPU hour for the period (in cents, 1 = $0.01). */ max: number; - /** @description The average price per GPU hour for the period (in centicents, 1/100th of a cent). */ + /** @description The average price per GPU hour for the period (in cents, 1 = $0.01). */ avg: number; }; /** @description ISO 8601 datetime marking the start of the period. */ @@ -286,11 +302,11 @@ export interface operations { /** @constant */ object: "price-history-item"; gpu_hour?: { - /** @description The minimum price per GPU hour for the period (in centicents, 1/100th of a cent). */ + /** @description The minimum price per GPU hour for the period (in cents, 1 = $0.01). */ min: number; - /** @description The maximum price per GPU hour for the period (in centicents, 1/100th of a cent). */ + /** @description The maximum price per GPU hour for the period (in cents, 1 = $0.01). */ max: number; - /** @description The average price per GPU hour for the period (in centicents, 1/100th of a cent). */ + /** @description The average price per GPU hour for the period (in cents, 1 = $0.01). */ avg: number; }; /** @description ISO 8601 datetime marking the start of the period. */ @@ -343,11 +359,11 @@ export interface operations { parameters: { query: { side: "buy" | "sell"; - /** @description Inclusive lower bound for the start time, as an ISO 8601 string. The query will consider all valid start times at or after this time. The difference between this and `max_start_time` can be at most 24 hours. */ - min_start_date: string; - /** @description Inclusive upper bound for the start time, as an ISO 8601 string. The query will consider all valid start times on or before this time. The difference between this and `min_start_time` can be at most 24 hours. */ - max_start_date: string; - /** @description The duration, in seconds. Duration will be rounded such that the contract ends on the hour. For example if `start_time` is 17:10 and you put in 30m, the duration will be rounded up to 50m. Similarly, if `start_time` is 18:00 and you put 50m, the duration will be rounded up to 1h. */ + /** @description Inclusive lower bound for the start time. Can either be the literal string "NOW" or an ISO 8601 string. The query will consider all valid start times at or after this time. The difference between this and `max_start_time` can be at most 24 hours. */ + min_start_date: "NOW" | string; + /** @description Inclusive upper bound for the start time. Can either be the literal string "NOW" or an ISO 8601 string. The query will consider all valid start times on or before this time. The difference between this and `min_start_time` can be at most 24 hours. */ + max_start_date: "NOW" | string; + /** @description desired duration, in seconds. Since contracts must end on the hour, the actual duration returned by the quote may be longer than the requested duration by up to 59 minutes. */ duration: number; /** @description The number of nodes. */ quantity: number; @@ -376,14 +392,14 @@ export interface operations { /** @constant */ side: "buy"; quote: { - /** @description Price in Centicents (1/100th of a cent, One Centicent = $0.0001) */ + /** @description Price in cents (1 = $0.01) */ price: number; /** @description The number of nodes. */ quantity: number; /** @description The start time, as an ISO 8601 string. Start times must be either "right now" or on the hour. Order start times must be in the future, and can be either the next minute from now or on the hour. For example, if it's 16:00, valid start times include 16:01, 17:00, and 18:00, but not 16:30. Dates are always rounded up to the nearest minute. */ start_at: string; - /** @description The duration, in seconds. Duration will be rounded such that the contract ends on the hour. For example if `start_time` is 17:10 and you put in 30m, the duration will be rounded up to 50m. Similarly, if `start_time` is 18:00 and you put 50m, the duration will be rounded up to 1h. */ - duration: number; + /** @description The end time, as an ISO 8601 string. End times must be on the hour, i.e. 16:00, 17:00, 18:00, etc. 17:30, 17:01, etc are not valid end times. Dates are always rounded up to the nearest minute. */ + end_at: string; /** @description The instance type. */ instance_type: string; } | null; @@ -394,14 +410,14 @@ export interface operations { /** @constant */ side: "sell"; quote: { - /** @description Price in Centicents (1/100th of a cent, One Centicent = $0.0001) */ + /** @description Price in cents (1 = $0.01) */ price: number; /** @description The number of nodes. */ quantity: number; /** @description The start time, as an ISO 8601 string. Start times must be either "right now" or on the hour. Order start times must be in the future, and can be either the next minute from now or on the hour. For example, if it's 16:00, valid start times include 16:01, 17:00, and 18:00, but not 16:30. Dates are always rounded up to the nearest minute. */ start_at: string; - /** @description The duration, in seconds. Duration will be rounded such that the contract ends on the hour. For example if `start_time` is 17:10 and you put in 30m, the duration will be rounded up to 50m. Similarly, if `start_time` is 18:00 and you put 50m, the duration will be rounded up to 1h. */ - duration: number; + /** @description The end time, as an ISO 8601 string. End times must be on the hour, i.e. 16:00, 17:00, 18:00, etc. 17:30, 17:01, etc are not valid end times. Dates are always rounded up to the nearest minute. */ + end_at: string; contract_id: string; } | null; }; @@ -412,14 +428,14 @@ export interface operations { /** @constant */ side: "buy"; quote: { - /** @description Price in Centicents (1/100th of a cent, One Centicent = $0.0001) */ + /** @description Price in cents (1 = $0.01) */ price: number; /** @description The number of nodes. */ quantity: number; /** @description The start time, as an ISO 8601 string. Start times must be either "right now" or on the hour. Order start times must be in the future, and can be either the next minute from now or on the hour. For example, if it's 16:00, valid start times include 16:01, 17:00, and 18:00, but not 16:30. Dates are always rounded up to the nearest minute. */ start_at: string; - /** @description The duration, in seconds. Duration will be rounded such that the contract ends on the hour. For example if `start_time` is 17:10 and you put in 30m, the duration will be rounded up to 50m. Similarly, if `start_time` is 18:00 and you put 50m, the duration will be rounded up to 1h. */ - duration: number; + /** @description The end time, as an ISO 8601 string. End times must be on the hour, i.e. 16:00, 17:00, 18:00, etc. 17:30, 17:01, etc are not valid end times. Dates are always rounded up to the nearest minute. */ + end_at: string; /** @description The instance type. */ instance_type: string; } | null; @@ -430,14 +446,14 @@ export interface operations { /** @constant */ side: "sell"; quote: { - /** @description Price in Centicents (1/100th of a cent, One Centicent = $0.0001) */ + /** @description Price in cents (1 = $0.01) */ price: number; /** @description The number of nodes. */ quantity: number; /** @description The start time, as an ISO 8601 string. Start times must be either "right now" or on the hour. Order start times must be in the future, and can be either the next minute from now or on the hour. For example, if it's 16:00, valid start times include 16:01, 17:00, and 18:00, but not 16:30. Dates are always rounded up to the nearest minute. */ start_at: string; - /** @description The duration, in seconds. Duration will be rounded such that the contract ends on the hour. For example if `start_time` is 17:10 and you put in 30m, the duration will be rounded up to 50m. Similarly, if `start_time` is 18:00 and you put 50m, the duration will be rounded up to 1h. */ - duration: number; + /** @description The end time, as an ISO 8601 string. End times must be on the hour, i.e. 16:00, 17:00, 18:00, etc. 17:30, 17:01, etc are not valid end times. Dates are always rounded up to the nearest minute. */ + end_at: string; contract_id: string; } | null; }; @@ -448,14 +464,14 @@ export interface operations { /** @constant */ side: "buy"; quote: { - /** @description Price in Centicents (1/100th of a cent, One Centicent = $0.0001) */ + /** @description Price in cents (1 = $0.01) */ price: number; /** @description The number of nodes. */ quantity: number; /** @description The start time, as an ISO 8601 string. Start times must be either "right now" or on the hour. Order start times must be in the future, and can be either the next minute from now or on the hour. For example, if it's 16:00, valid start times include 16:01, 17:00, and 18:00, but not 16:30. Dates are always rounded up to the nearest minute. */ start_at: string; - /** @description The duration, in seconds. Duration will be rounded such that the contract ends on the hour. For example if `start_time` is 17:10 and you put in 30m, the duration will be rounded up to 50m. Similarly, if `start_time` is 18:00 and you put 50m, the duration will be rounded up to 1h. */ - duration: number; + /** @description The end time, as an ISO 8601 string. End times must be on the hour, i.e. 16:00, 17:00, 18:00, etc. 17:30, 17:01, etc are not valid end times. Dates are always rounded up to the nearest minute. */ + end_at: string; /** @description The instance type. */ instance_type: string; } | null; @@ -466,14 +482,14 @@ export interface operations { /** @constant */ side: "sell"; quote: { - /** @description Price in Centicents (1/100th of a cent, One Centicent = $0.0001) */ + /** @description Price in cents (1 = $0.01) */ price: number; /** @description The number of nodes. */ quantity: number; /** @description The start time, as an ISO 8601 string. Start times must be either "right now" or on the hour. Order start times must be in the future, and can be either the next minute from now or on the hour. For example, if it's 16:00, valid start times include 16:01, 17:00, and 18:00, but not 16:30. Dates are always rounded up to the nearest minute. */ start_at: string; - /** @description The duration, in seconds. Duration will be rounded such that the contract ends on the hour. For example if `start_time` is 17:10 and you put in 30m, the duration will be rounded up to 50m. Similarly, if `start_time` is 18:00 and you put 50m, the duration will be rounded up to 1h. */ - duration: number; + /** @description The end time, as an ISO 8601 string. End times must be on the hour, i.e. 16:00, 17:00, 18:00, etc. 17:30, 17:01, etc are not valid end times. Dates are always rounded up to the nearest minute. */ + end_at: string; contract_id: string; } | null; }; @@ -612,11 +628,10 @@ export interface operations { instance_type: string; /** @description The number of nodes. */ quantity: number; - /** @description The start time, as an ISO 8601 string. Start times must be either "right now" or on the hour. Order start times must be in the future, and can be either the next minute from now or on the hour. For example, if it's 16:00, valid start times include 16:01, 17:00, and 18:00, but not 16:30. Dates are always rounded up to the nearest minute. */ - start_at: string; + start_at: string | "NOW"; /** @description The end time, as an ISO 8601 string. End times must be on the hour, i.e. 16:00, 17:00, 18:00, etc. 17:30, 17:01, etc are not valid end times. Dates are always rounded up to the nearest minute. */ end_at: string; - /** @description Price in Centicents (1/100th of a cent, One Centicent = $0.0001) */ + /** @description Price in cents (1 = $0.01) */ price: number; flags?: { /** @description If true, this will be a market order. */ @@ -634,11 +649,10 @@ export interface operations { contract_id: string; /** @description The number of nodes. */ quantity: number; - /** @description The start time, as an ISO 8601 string. Start times must be either "right now" or on the hour. Order start times must be in the future, and can be either the next minute from now or on the hour. For example, if it's 16:00, valid start times include 16:01, 17:00, and 18:00, but not 16:30. Dates are always rounded up to the nearest minute. */ - start_at: string; + start_at: string | "NOW"; /** @description The end time, as an ISO 8601 string. End times must be on the hour, i.e. 16:00, 17:00, 18:00, etc. 17:30, 17:01, etc are not valid end times. Dates are always rounded up to the nearest minute. */ end_at: string; - /** @description Price in Centicents (1/100th of a cent, One Centicent = $0.0001) */ + /** @description Price in cents (1 = $0.01) */ price: number; flags?: { /** @description If true, this will be a market order. */ @@ -654,7 +668,7 @@ export interface operations { * @constant */ strategy: "linear"; - /** @description For sell orders, the floor (lowest) price the order can be adjusted to, in centicents. For buy orders, the ceiling (highest) price the order can be adjusted to. */ + /** @description For sell orders, the floor (lowest) price the order can be adjusted to, in cents. For buy orders, the ceiling (highest) price the order can be adjusted to. */ limit: number; /** @description When to start adjusting the order’s price. If this date is in the past, it will be clamped such that the adjustment starts immediately. */ start_at?: string; @@ -670,11 +684,10 @@ export interface operations { instance_type: string; /** @description The number of nodes. */ quantity: number; - /** @description The start time, as an ISO 8601 string. Start times must be either "right now" or on the hour. Order start times must be in the future, and can be either the next minute from now or on the hour. For example, if it's 16:00, valid start times include 16:01, 17:00, and 18:00, but not 16:30. Dates are always rounded up to the nearest minute. */ - start_at: string; + start_at: string | "NOW"; /** @description The end time, as an ISO 8601 string. End times must be on the hour, i.e. 16:00, 17:00, 18:00, etc. 17:30, 17:01, etc are not valid end times. Dates are always rounded up to the nearest minute. */ end_at: string; - /** @description Price in Centicents (1/100th of a cent, One Centicent = $0.0001) */ + /** @description Price in cents (1 = $0.01) */ price: number; flags?: { /** @description If true, this will be a market order. */ @@ -692,11 +705,10 @@ export interface operations { contract_id: string; /** @description The number of nodes. */ quantity: number; - /** @description The start time, as an ISO 8601 string. Start times must be either "right now" or on the hour. Order start times must be in the future, and can be either the next minute from now or on the hour. For example, if it's 16:00, valid start times include 16:01, 17:00, and 18:00, but not 16:30. Dates are always rounded up to the nearest minute. */ - start_at: string; + start_at: string | "NOW"; /** @description The end time, as an ISO 8601 string. End times must be on the hour, i.e. 16:00, 17:00, 18:00, etc. 17:30, 17:01, etc are not valid end times. Dates are always rounded up to the nearest minute. */ end_at: string; - /** @description Price in Centicents (1/100th of a cent, One Centicent = $0.0001) */ + /** @description Price in cents (1 = $0.01) */ price: number; flags?: { /** @description If true, this will be a market order. */ @@ -712,7 +724,7 @@ export interface operations { * @constant */ strategy: "linear"; - /** @description For sell orders, the floor (lowest) price the order can be adjusted to, in centicents. For buy orders, the ceiling (highest) price the order can be adjusted to. */ + /** @description For sell orders, the floor (lowest) price the order can be adjusted to, in cents. For buy orders, the ceiling (highest) price the order can be adjusted to. */ limit: number; /** @description When to start adjusting the order’s price. If this date is in the past, it will be clamped such that the adjustment starts immediately. */ start_at?: string; @@ -728,11 +740,10 @@ export interface operations { instance_type: string; /** @description The number of nodes. */ quantity: number; - /** @description The start time, as an ISO 8601 string. Start times must be either "right now" or on the hour. Order start times must be in the future, and can be either the next minute from now or on the hour. For example, if it's 16:00, valid start times include 16:01, 17:00, and 18:00, but not 16:30. Dates are always rounded up to the nearest minute. */ - start_at: string; + start_at: string | "NOW"; /** @description The end time, as an ISO 8601 string. End times must be on the hour, i.e. 16:00, 17:00, 18:00, etc. 17:30, 17:01, etc are not valid end times. Dates are always rounded up to the nearest minute. */ end_at: string; - /** @description Price in Centicents (1/100th of a cent, One Centicent = $0.0001) */ + /** @description Price in cents (1 = $0.01) */ price: number; flags?: { /** @description If true, this will be a market order. */ @@ -750,11 +761,10 @@ export interface operations { contract_id: string; /** @description The number of nodes. */ quantity: number; - /** @description The start time, as an ISO 8601 string. Start times must be either "right now" or on the hour. Order start times must be in the future, and can be either the next minute from now or on the hour. For example, if it's 16:00, valid start times include 16:01, 17:00, and 18:00, but not 16:30. Dates are always rounded up to the nearest minute. */ - start_at: string; + start_at: string | "NOW"; /** @description The end time, as an ISO 8601 string. End times must be on the hour, i.e. 16:00, 17:00, 18:00, etc. 17:30, 17:01, etc are not valid end times. Dates are always rounded up to the nearest minute. */ end_at: string; - /** @description Price in Centicents (1/100th of a cent, One Centicent = $0.0001) */ + /** @description Price in cents (1 = $0.01) */ price: number; flags?: { /** @description If true, this will be a market order. */ @@ -770,7 +780,7 @@ export interface operations { * @constant */ strategy: "linear"; - /** @description For sell orders, the floor (lowest) price the order can be adjusted to, in centicents. For buy orders, the ceiling (highest) price the order can be adjusted to. */ + /** @description For sell orders, the floor (lowest) price the order can be adjusted to, in cents. For buy orders, the ceiling (highest) price the order can be adjusted to. */ limit: number; /** @description When to start adjusting the order’s price. If this date is in the past, it will be clamped such that the adjustment starts immediately. */ start_at?: string; @@ -912,7 +922,7 @@ export interface operations { start_at: string; /** @description The end time, as an ISO 8601 string. End times must be on the hour, i.e. 16:00, 17:00, 18:00, etc. 17:30, 17:01, etc are not valid end times. Dates are always rounded up to the nearest minute. */ end_at: string; - /** @description Price in Centicents (1/100th of a cent, One Centicent = $0.0001) */ + /** @description Price in cents (1 = $0.01) */ price: number; flags: { /** @description If true, this will be a market order. */ @@ -924,7 +934,7 @@ export interface operations { }; executed: boolean; executed_at?: string; - /** @description Execution price in Centicents (1/100th of a cent, One Centicent = $0.0001) */ + /** @description Execution price in cents (1 = $0.01) */ execution_price?: number; cancelled: boolean; cancelled_at?: string; @@ -951,7 +961,7 @@ export interface operations { start_at: string; /** @description The end time, as an ISO 8601 string. End times must be on the hour, i.e. 16:00, 17:00, 18:00, etc. 17:30, 17:01, etc are not valid end times. Dates are always rounded up to the nearest minute. */ end_at: string; - /** @description Price in Centicents (1/100th of a cent, One Centicent = $0.0001) */ + /** @description Price in cents (1 = $0.01) */ price: number; flags: { /** @description If true, this will be a market order. */ @@ -963,7 +973,7 @@ export interface operations { }; executed: boolean; executed_at?: string; - /** @description Execution price in Centicents (1/100th of a cent, One Centicent = $0.0001) */ + /** @description Execution price in cents (1 = $0.01) */ execution_price?: number; cancelled: boolean; cancelled_at?: string; @@ -990,7 +1000,7 @@ export interface operations { start_at: string; /** @description The end time, as an ISO 8601 string. End times must be on the hour, i.e. 16:00, 17:00, 18:00, etc. 17:30, 17:01, etc are not valid end times. Dates are always rounded up to the nearest minute. */ end_at: string; - /** @description Price in Centicents (1/100th of a cent, One Centicent = $0.0001) */ + /** @description Price in cents (1 = $0.01) */ price: number; flags: { /** @description If true, this will be a market order. */ @@ -1002,7 +1012,7 @@ export interface operations { }; executed: boolean; executed_at?: string; - /** @description Execution price in Centicents (1/100th of a cent, One Centicent = $0.0001) */ + /** @description Execution price in cents (1 = $0.01) */ execution_price?: number; cancelled: boolean; cancelled_at?: string; @@ -1172,6 +1182,101 @@ export interface operations { }; }; }; + "postV0OrdersCancel-all": { + parameters: { + query?: never; + header?: { + /** @description Generate a bearer token with `$ sf tokens create`. */ + authorization?: string; + }; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + /** @constant */ + object: "pending"; + }; + "multipart/form-data": { + /** @constant */ + object: "pending"; + }; + "text/plain": { + /** @constant */ + object: "pending"; + }; + }; + }; + 401: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + /** @constant */ + object: "error"; + /** @constant */ + code: "not_authenticated"; + message: string; + details?: Record; + }; + "multipart/form-data": { + /** @constant */ + object: "error"; + /** @constant */ + code: "not_authenticated"; + message: string; + details?: Record; + }; + "text/plain": { + /** @constant */ + object: "error"; + /** @constant */ + code: "not_authenticated"; + message: string; + details?: Record; + }; + }; + }; + 500: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + /** @constant */ + object: "error"; + /** @constant */ + code: "internal_server"; + message: string; + details?: Record; + }; + "multipart/form-data": { + /** @constant */ + object: "error"; + /** @constant */ + code: "internal_server"; + message: string; + details?: Record; + }; + "text/plain": { + /** @constant */ + object: "error"; + /** @constant */ + code: "internal_server"; + message: string; + details?: Record; + }; + }; + }; + }; + }; getV0Instances: { parameters: { query?: never; @@ -2479,21 +2584,21 @@ export interface operations { content: { "application/json": { quantity?: number; - /** @description The price (in centicents) per node per hour */ + /** @description The price (in cents) per node per hour */ max_price_per_node_hour?: number; /** @description The block duration of the procurement in hours */ min_duration_in_hours?: number; }; "multipart/form-data": { quantity?: number; - /** @description The price (in centicents) per node per hour */ + /** @description The price (in cents) per node per hour */ max_price_per_node_hour?: number; /** @description The block duration of the procurement in hours */ min_duration_in_hours?: number; }; "text/plain": { quantity?: number; - /** @description The price (in centicents) per node per hour */ + /** @description The price (in cents) per node per hour */ max_price_per_node_hour?: number; /** @description The block duration of the procurement in hours */ min_duration_in_hours?: number;