mirror of
https://github.com/d0zingcat/solana-agent-kit.git
synced 2026-05-17 15:10:27 +00:00
feat: update to hermes v2
This commit is contained in:
@@ -198,11 +198,11 @@ import { PublicKey } from "@solana/web3.js";
|
||||
|
||||
```typescript
|
||||
|
||||
const price = await agent.pythFetchPrice(
|
||||
"0xe62df6c8b4a85fe1a67db44dc12de5db330f7ac66b72dc658afedf0f4a415b43"
|
||||
);
|
||||
const priceFeedID = await agent.getPythPriceFeedID("SOL");
|
||||
|
||||
console.log("Price in BTC/USD:", price);
|
||||
const price = await agent.getPythPrice(priceFeedID);
|
||||
|
||||
console.log("Price of SOL/USD:", price);
|
||||
```
|
||||
|
||||
## Examples
|
||||
@@ -233,7 +233,6 @@ The toolkit relies on several key Solana and Metaplex libraries:
|
||||
- @metaplex-foundation/umi
|
||||
- @lightprotocol/compressed-token
|
||||
- @lightprotocol/stateless.js
|
||||
- @pythnetwork/price-service-client
|
||||
|
||||
## Contributing
|
||||
|
||||
|
||||
@@ -5,24 +5,24 @@ import { createReactAgent } from "@langchain/langgraph/prebuilt";
|
||||
import { SolanaAgentKit, createSolanaTools } from "solana-agent-kit";
|
||||
|
||||
const llm = new ChatOpenAI({
|
||||
temperature: 0.7,
|
||||
model: "gpt-4o-mini",
|
||||
temperature: 0.7,
|
||||
model: "gpt-4o-mini",
|
||||
});
|
||||
|
||||
const solanaAgent = new SolanaAgentKit(
|
||||
process.env.SOLANA_PRIVATE_KEY!,
|
||||
process.env.RPC_URL,
|
||||
process.env.OPENAI_API_KEY!,
|
||||
process.env.SOLANA_PRIVATE_KEY!,
|
||||
process.env.RPC_URL,
|
||||
process.env.OPENAI_API_KEY!,
|
||||
);
|
||||
|
||||
const tools = createSolanaTools(solanaAgent);
|
||||
const memory = new MemorySaver();
|
||||
|
||||
const agent = createReactAgent({
|
||||
llm,
|
||||
tools,
|
||||
checkpointSaver: memory,
|
||||
messageModifier: `
|
||||
llm,
|
||||
tools,
|
||||
checkpointSaver: memory,
|
||||
messageModifier: `
|
||||
You are a helpful agent that can interact onchain using the Solana Agent Kit. You are
|
||||
empowered to interact onchain using your tools. If you ever need funds, you can request them from the
|
||||
faucet. If not, you can provide your wallet details and request funds from the user. If there is a 5XX
|
||||
@@ -34,38 +34,38 @@ const agent = createReactAgent({
|
||||
});
|
||||
|
||||
export async function POST(req: NextRequest) {
|
||||
try {
|
||||
const body = await req.json();
|
||||
const messages = body.messages ?? [];
|
||||
try {
|
||||
const body = await req.json();
|
||||
const messages = body.messages ?? [];
|
||||
|
||||
const eventStream = agent.streamEvents(
|
||||
{
|
||||
messages,
|
||||
},
|
||||
{
|
||||
version: "v2",
|
||||
configurable: {
|
||||
thread_id: "Solana Agent Kit!",
|
||||
},
|
||||
},
|
||||
);
|
||||
const eventStream = agent.streamEvents(
|
||||
{
|
||||
messages,
|
||||
},
|
||||
{
|
||||
version: "v2",
|
||||
configurable: {
|
||||
thread_id: "Solana Agent Kit!",
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
const textEncoder = new TextEncoder();
|
||||
const transformStream = new ReadableStream({
|
||||
async start(controller) {
|
||||
for await (const { event, data } of eventStream) {
|
||||
if (event === "on_chat_model_stream") {
|
||||
if (!!data.chunk.content) {
|
||||
controller.enqueue(textEncoder.encode(data.chunk.content));
|
||||
}
|
||||
}
|
||||
}
|
||||
controller.close();
|
||||
},
|
||||
});
|
||||
const textEncoder = new TextEncoder();
|
||||
const transformStream = new ReadableStream({
|
||||
async start(controller) {
|
||||
for await (const { event, data } of eventStream) {
|
||||
if (event === "on_chat_model_stream") {
|
||||
if (data.chunk.content) {
|
||||
controller.enqueue(textEncoder.encode(data.chunk.content));
|
||||
}
|
||||
}
|
||||
}
|
||||
controller.close();
|
||||
},
|
||||
});
|
||||
|
||||
return new Response(transformStream);
|
||||
} catch (e: any) {
|
||||
return NextResponse.json({ error: e.message }, { status: e.status ?? 500 });
|
||||
}
|
||||
return new Response(transformStream);
|
||||
} catch (e: any) {
|
||||
return NextResponse.json({ error: e.message }, { status: e.status ?? 500 });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -537,4 +537,4 @@ const executor = await initializeAgentExecutorWithOptions(tools, llm, {
|
||||
},
|
||||
});
|
||||
\`\`\`
|
||||
`;
|
||||
`;
|
||||
|
||||
@@ -2,29 +2,29 @@ import { marked } from "marked";
|
||||
import DOMPurify from "isomorphic-dompurify";
|
||||
|
||||
interface MarkedOptions {
|
||||
gfm: boolean;
|
||||
breaks: boolean;
|
||||
headerIds: boolean;
|
||||
mangle: false;
|
||||
highlight?: (code: string, lang: string) => string;
|
||||
gfm: boolean;
|
||||
breaks: boolean;
|
||||
headerIds: boolean;
|
||||
mangle: false;
|
||||
highlight?: (code: string, lang: string) => string;
|
||||
}
|
||||
|
||||
// Configure marked options
|
||||
const markedOptions: MarkedOptions = {
|
||||
gfm: true, // GitHub Flavored Markdown
|
||||
breaks: true, // Convert \n to <br>
|
||||
headerIds: true, // Add ids to headers
|
||||
mangle: false, // Don't escape HTML
|
||||
highlight: function (code: string, lang: string): string {
|
||||
// You can add syntax highlighting here if needed
|
||||
return code;
|
||||
},
|
||||
gfm: true, // GitHub Flavored Markdown
|
||||
breaks: true, // Convert \n to <br>
|
||||
headerIds: true, // Add ids to headers
|
||||
mangle: false, // Don't escape HTML
|
||||
highlight: function (code: string, lang: string): string {
|
||||
// You can add syntax highlighting here if needed
|
||||
return code;
|
||||
},
|
||||
};
|
||||
|
||||
marked.setOptions(markedOptions);
|
||||
|
||||
// Basic markdown to HTML conversion with sanitization
|
||||
export default function markdownToHtml(markdown: string) {
|
||||
const rawHtml = marked.parse(markdown);
|
||||
return DOMPurify.sanitize(rawHtml as string);
|
||||
const rawHtml = marked.parse(markdown);
|
||||
return DOMPurify.sanitize(rawHtml as string);
|
||||
}
|
||||
|
||||
@@ -39,7 +39,6 @@
|
||||
"@onsol/tldparser": "^0.6.7",
|
||||
"@orca-so/common-sdk": "0.6.4",
|
||||
"@orca-so/whirlpools-sdk": "^0.13.12",
|
||||
"@pythnetwork/price-service-client": "^1.9.0",
|
||||
"@raydium-io/raydium-sdk-v2": "0.1.95-alpha",
|
||||
"@solana/spl-token": "^0.4.9",
|
||||
"@tensor-oss/tensorswap-sdk": "^4.5.0",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Action } from "../types/action";
|
||||
import { SolanaAgentKit } from "../agent";
|
||||
import { z } from "zod";
|
||||
import { pythFetchPrice } from "../tools";
|
||||
import { fetchPythPrice, fetchPythPriceFeedID } from "../tools";
|
||||
|
||||
const pythFetchPriceAction: Action = {
|
||||
name: "PYTH_FETCH_PRICE",
|
||||
@@ -18,7 +18,7 @@ const pythFetchPriceAction: Action = {
|
||||
[
|
||||
{
|
||||
input: {
|
||||
priceFeedId: "Gnt27xtC473ZT2Mw5u8wZ68Z3gULkSTb5DuxJy7eJotD", // SOL/USD price feed
|
||||
tokenSymbol: "SOL", // SOL/USD price feed
|
||||
},
|
||||
output: {
|
||||
status: "success",
|
||||
@@ -37,8 +37,10 @@ const pythFetchPriceAction: Action = {
|
||||
}),
|
||||
handler: async (_agent: SolanaAgentKit, input: Record<string, any>) => {
|
||||
try {
|
||||
const priceFeedId = input.tokenId as string;
|
||||
const priceStr = await pythFetchPrice(priceFeedId);
|
||||
const priceFeedId = await fetchPythPriceFeedID(input.tokenSymbol);
|
||||
|
||||
const priceStr = await fetchPythPrice(priceFeedId);
|
||||
|
||||
return {
|
||||
status: "success",
|
||||
price: priceStr,
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { Connection, Keypair, PublicKey } from "@solana/web3.js";
|
||||
import { BN } from "@coral-xyz/anchor";
|
||||
import bs58 from "bs58";
|
||||
import Decimal from "decimal.js";
|
||||
import { DEFAULT_OPTIONS } from "../constants";
|
||||
@@ -37,7 +38,6 @@ import {
|
||||
orcaOpenSingleSidedPosition,
|
||||
FEE_TIERS,
|
||||
fetchPrice,
|
||||
pythFetchPrice,
|
||||
getAllDomainsTLDs,
|
||||
getAllRegisteredAllDomains,
|
||||
getOwnedDomainsForTLD,
|
||||
@@ -53,9 +53,9 @@ import {
|
||||
cancelListing,
|
||||
fetchTokenReportSummary,
|
||||
fetchTokenDetailedReport,
|
||||
OrderParams,
|
||||
fetchPythPrice,
|
||||
fetchPythPriceFeedID,
|
||||
} from "../tools";
|
||||
|
||||
import {
|
||||
CollectionDeployment,
|
||||
CollectionOptions,
|
||||
@@ -64,8 +64,8 @@ import {
|
||||
MintCollectionNFTResponse,
|
||||
PumpfunLaunchResponse,
|
||||
PumpFunTokenOptions,
|
||||
OrderParams,
|
||||
} from "../types";
|
||||
import { BN } from "@coral-xyz/anchor";
|
||||
|
||||
/**
|
||||
* Main class for interacting with Solana blockchain
|
||||
@@ -442,8 +442,12 @@ export class SolanaAgentKit {
|
||||
return manifestCreateMarket(this, baseMint, quoteMint);
|
||||
}
|
||||
|
||||
async pythFetchPrice(priceFeedID: string): Promise<string> {
|
||||
return pythFetchPrice(priceFeedID);
|
||||
async getPythPriceFeedID(tokenSymbol: string): Promise<string> {
|
||||
return fetchPythPriceFeedID(tokenSymbol);
|
||||
}
|
||||
|
||||
async getPythPrice(priceFeedID: string): Promise<string> {
|
||||
return fetchPythPrice(priceFeedID);
|
||||
}
|
||||
|
||||
async createGibworkTask(
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
import { PublicKey } from "@solana/web3.js";
|
||||
import { BN } from "@coral-xyz/anchor";
|
||||
import Decimal from "decimal.js";
|
||||
import { Tool } from "langchain/tools";
|
||||
import {
|
||||
GibworkCreateTaskReponse,
|
||||
OrderParams,
|
||||
PythFetchPriceResponse,
|
||||
SolanaAgentKit,
|
||||
} from "../index";
|
||||
import { create_image } from "../tools/create_image";
|
||||
import { BN } from "@coral-xyz/anchor";
|
||||
import { FEE_TIERS, generateOrdersfromPattern, OrderParams } from "../tools";
|
||||
import { create_image, FEE_TIERS, generateOrdersfromPattern } from "../tools";
|
||||
|
||||
export class SolanaBalanceTool extends Tool {
|
||||
name = "solana_balance";
|
||||
@@ -1497,7 +1497,7 @@ export class SolanaPythFetchPrice extends Tool {
|
||||
description = `Fetch the price of a given price feed from Pyth's Hermes service
|
||||
|
||||
Inputs:
|
||||
priceFeedID: string, the price feed ID, e.g., "0xe62df6c8b4a85fe1a67db44dc12de5db330f7ac66b72dc658afedf0f4a415b43" for BTC/USD`;
|
||||
tokenSymbol: string, e.g., BTC for bitcoin`;
|
||||
|
||||
constructor(private solanaKit: SolanaAgentKit) {
|
||||
super();
|
||||
@@ -1505,17 +1505,21 @@ export class SolanaPythFetchPrice extends Tool {
|
||||
|
||||
async _call(input: string): Promise<string> {
|
||||
try {
|
||||
const price = await this.solanaKit.pythFetchPrice(input);
|
||||
const priceFeedID = await this.solanaKit.getPythPriceFeedID(input);
|
||||
const price = await this.solanaKit.getPythPrice(priceFeedID);
|
||||
|
||||
const response: PythFetchPriceResponse = {
|
||||
status: "success",
|
||||
priceFeedID: input,
|
||||
tokenSymbol: input,
|
||||
priceFeedID,
|
||||
price,
|
||||
};
|
||||
|
||||
return JSON.stringify(response);
|
||||
} catch (error: any) {
|
||||
const response: PythFetchPriceResponse = {
|
||||
status: "error",
|
||||
priceFeedID: input,
|
||||
tokenSymbol: input,
|
||||
message: error.message,
|
||||
code: error.code || "UNKNOWN_ERROR",
|
||||
};
|
||||
|
||||
@@ -4,33 +4,13 @@ import {
|
||||
sendAndConfirmTransaction,
|
||||
TransactionInstruction,
|
||||
} from "@solana/web3.js";
|
||||
import { SolanaAgentKit } from "../index";
|
||||
import {
|
||||
ManifestClient,
|
||||
WrapperPlaceOrderParamsExternal,
|
||||
} from "@cks-systems/manifest-sdk";
|
||||
import { OrderType } from "@cks-systems/manifest-sdk/client/ts/src/wrapper/types/OrderType";
|
||||
|
||||
export interface OrderParams {
|
||||
quantity: number;
|
||||
side: string;
|
||||
price: number;
|
||||
}
|
||||
|
||||
interface BatchOrderPattern {
|
||||
side: string;
|
||||
totalQuantity?: number;
|
||||
priceRange?: {
|
||||
min?: number;
|
||||
max?: number;
|
||||
};
|
||||
spacing?: {
|
||||
type: "percentage" | "fixed";
|
||||
value: number;
|
||||
};
|
||||
numberOfOrders?: number;
|
||||
individualQuantity?: number;
|
||||
}
|
||||
import { SolanaAgentKit } from "../index";
|
||||
import { BatchOrderPattern, OrderParams } from "../types";
|
||||
|
||||
/**
|
||||
* Generates an array of orders based on the specified pattern
|
||||
|
||||
@@ -1,58 +1,46 @@
|
||||
import exp from "constants";
|
||||
|
||||
export * from "./request_faucet_funds";
|
||||
export * from "./deploy_token";
|
||||
export * from "./deploy_collection";
|
||||
export * from "./get_balance";
|
||||
export * from "./get_balance_other";
|
||||
export * from "./mint_nft";
|
||||
export * from "./transfer";
|
||||
export * from "./trade";
|
||||
export * from "./limit_order";
|
||||
export * from "./batch_order";
|
||||
export * from "./cancel_all_orders";
|
||||
export * from "./withdraw_all";
|
||||
export * from "./register_domain";
|
||||
export * from "./resolve_sol_domain";
|
||||
export * from "./create_gibwork_task";
|
||||
export * from "./create_image";
|
||||
export * from "./create_tiplinks";
|
||||
export * from "./deploy_collection";
|
||||
export * from "./deploy_token";
|
||||
export * from "./fetch_price";
|
||||
export * from "./get_all_domains_tlds";
|
||||
export * from "./get_all_registered_all_domains";
|
||||
export * from "./get_balance";
|
||||
export * from "./get_balance_other";
|
||||
export * from "./get_main_all_domains_domain";
|
||||
export * from "./get_owned_all_domains";
|
||||
export * from "./get_owned_domains_for_tld";
|
||||
export * from "./get_primary_domain";
|
||||
export * from "./get_token_data";
|
||||
export * from "./get_tps";
|
||||
export * from "./launch_pumpfun_token";
|
||||
export * from "./lend";
|
||||
export * from "./get_tps";
|
||||
export * from "./get_token_data";
|
||||
export * from "./stake_with_jup";
|
||||
export * from "./fetch_price";
|
||||
export * from "./send_compressed_airdrop";
|
||||
export * from "./limit_order";
|
||||
export * from "./manifest_create_market";
|
||||
export * from "./mint_nft";
|
||||
export * from "./openbook_create_market";
|
||||
export * from "./orca_close_position";
|
||||
export * from "./orca_create_clmm";
|
||||
export * from "./orca_create_single_sided_liquidity_pool";
|
||||
export * from "./orca_fetch_positions";
|
||||
export * from "./orca_open_centered_position_with_liquidity";
|
||||
export * from "./orca_open_single_sided_position";
|
||||
export * from "./get_all_domains_tlds";
|
||||
export * from "./get_all_registered_all_domains";
|
||||
export * from "./get_owned_domains_for_tld";
|
||||
export * from "./get_main_all_domains_domain";
|
||||
export * from "./get_owned_all_domains";
|
||||
export * from "./resolve_domain";
|
||||
|
||||
export * from "./get_all_domains_tlds";
|
||||
export * from "./get_all_registered_all_domains";
|
||||
export * from "./get_owned_domains_for_tld";
|
||||
export * from "./get_main_all_domains_domain";
|
||||
export * from "./get_owned_all_domains";
|
||||
export * from "./resolve_domain";
|
||||
|
||||
export * from "./pyth_fetch_price";
|
||||
export * from "./raydium_create_ammV4";
|
||||
export * from "./raydium_create_clmm";
|
||||
export * from "./raydium_create_cpmm";
|
||||
export * from "./openbook_create_market";
|
||||
export * from "./manifest_create_market";
|
||||
export * from "./pyth_fetch_price";
|
||||
|
||||
export * from "./create_gibwork_task";
|
||||
|
||||
export * from "./register_domain";
|
||||
export * from "./request_faucet_funds";
|
||||
export * from "./resolve_domain";
|
||||
export * from "./resolve_sol_domain";
|
||||
export * from "./rock_paper_scissor";
|
||||
export * from "./create_tiplinks";
|
||||
|
||||
export * from "./tensor_trade";
|
||||
export * from "./rugcheck";
|
||||
export * from "./send_compressed_airdrop";
|
||||
export * from "./stake_with_jup";
|
||||
export * from "./tensor_trade";
|
||||
export * from "./trade";
|
||||
export * from "./transfer";
|
||||
export * from "./withdraw_all";
|
||||
|
||||
@@ -1,5 +1,51 @@
|
||||
import { PriceServiceConnection } from "@pythnetwork/price-service-client";
|
||||
import BN from "bn.js";
|
||||
import { PythPriceFeedIDItem } from "../types";
|
||||
|
||||
/**
|
||||
* Fetch the price feed ID for a given token symbol from Pyth
|
||||
* @param tokenSymbol Token symbol
|
||||
* @returns Price feed ID
|
||||
*/
|
||||
export async function fetchPythPriceFeedID(
|
||||
tokenSymbol: string,
|
||||
): Promise<string> {
|
||||
try {
|
||||
const stableHermesServiceUrl: string = "https://hermes.pyth.network";
|
||||
|
||||
const response = await fetch(
|
||||
`${stableHermesServiceUrl}/v2/price_feeds/?query=${tokenSymbol}&asset_type=crypto`,
|
||||
);
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(`HTTP error! status: ${response.status}`);
|
||||
}
|
||||
|
||||
const data = await response.json();
|
||||
|
||||
if (data.length === 0) {
|
||||
throw new Error(`No price feed found for ${tokenSymbol}`);
|
||||
}
|
||||
|
||||
if (data.length > 1) {
|
||||
const filteredData = data.filter(
|
||||
(item: PythPriceFeedIDItem) =>
|
||||
item.attributes.base.toLowerCase() === tokenSymbol.toLowerCase(),
|
||||
);
|
||||
|
||||
if (filteredData.length === 0) {
|
||||
throw new Error(`No price feed found for ${tokenSymbol}`);
|
||||
}
|
||||
|
||||
return filteredData[0].id;
|
||||
}
|
||||
|
||||
return data[0].id;
|
||||
} catch (error: any) {
|
||||
throw new Error(
|
||||
`Fetching price feed ID from Pyth failed: ${error.message}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch the price of a given price feed from Pyth
|
||||
@@ -9,28 +55,25 @@ import BN from "bn.js";
|
||||
*
|
||||
* You can find priceFeedIDs here: https://www.pyth.network/developers/price-feed-ids#stable
|
||||
*/
|
||||
export async function pythFetchPrice(priceFeedID: string): Promise<string> {
|
||||
// get Hermes service URL from https://docs.pyth.network/price-feeds/api-instances-and-providers/hermes
|
||||
const stableHermesServiceUrl: string = "https://hermes.pyth.network";
|
||||
const connection = new PriceServiceConnection(stableHermesServiceUrl);
|
||||
const feeds = [priceFeedID];
|
||||
|
||||
export async function fetchPythPrice(feedID: string): Promise<string> {
|
||||
try {
|
||||
const currentPrice = await connection.getLatestPriceFeeds(feeds);
|
||||
const stableHermesServiceUrl: string = "https://hermes.pyth.network";
|
||||
|
||||
if (currentPrice === undefined) {
|
||||
throw new Error("Price data not available for the given token.");
|
||||
const response = await fetch(
|
||||
`${stableHermesServiceUrl}/v2/updates/price/latest/?ids[]=${feedID}`,
|
||||
);
|
||||
|
||||
const data = await response.json();
|
||||
|
||||
const parsedData = data.parsed;
|
||||
|
||||
if (parsedData.length === 0) {
|
||||
throw new Error(`No price data found for ${feedID}`);
|
||||
}
|
||||
|
||||
if (currentPrice.length === 0) {
|
||||
throw new Error("Price data not available for the given token.");
|
||||
}
|
||||
const price = new BN(parsedData[0].price.price);
|
||||
const exponent = new BN(parsedData[0].price.expo);
|
||||
|
||||
// get price and exponent from price feed
|
||||
const price = new BN(currentPrice[0].getPriceUnchecked().price);
|
||||
const exponent = new BN(currentPrice[0].getPriceUnchecked().expo);
|
||||
|
||||
// convert to scaled price
|
||||
const scaledPrice = price.div(new BN(10).pow(exponent));
|
||||
|
||||
return scaledPrice.toString();
|
||||
|
||||
@@ -88,7 +88,8 @@ export interface FetchPriceResponse {
|
||||
|
||||
export interface PythFetchPriceResponse {
|
||||
status: "success" | "error";
|
||||
priceFeedID: string;
|
||||
tokenSymbol: string;
|
||||
priceFeedID?: string;
|
||||
price?: string;
|
||||
message?: string;
|
||||
code?: string;
|
||||
@@ -165,3 +166,61 @@ export interface TokenCheck {
|
||||
}>;
|
||||
score: number;
|
||||
}
|
||||
|
||||
export interface PythPriceFeedIDItem {
|
||||
id: string;
|
||||
attributes: {
|
||||
asset_type: string;
|
||||
base: string;
|
||||
};
|
||||
}
|
||||
|
||||
export interface PythPriceItem {
|
||||
binary: {
|
||||
data: string[];
|
||||
encoding: string;
|
||||
};
|
||||
parsed: [
|
||||
Array<{
|
||||
id: string;
|
||||
price: {
|
||||
price: string;
|
||||
conf: string;
|
||||
expo: number;
|
||||
publish_time: number;
|
||||
};
|
||||
ema_price: {
|
||||
price: string;
|
||||
conf: string;
|
||||
expo: number;
|
||||
publish_time: number;
|
||||
};
|
||||
metadata: {
|
||||
slot: number;
|
||||
proof_available_time: number;
|
||||
prev_publish_time: number;
|
||||
};
|
||||
}>,
|
||||
];
|
||||
}
|
||||
|
||||
export interface OrderParams {
|
||||
quantity: number;
|
||||
side: string;
|
||||
price: number;
|
||||
}
|
||||
|
||||
export interface BatchOrderPattern {
|
||||
side: string;
|
||||
totalQuantity?: number;
|
||||
priceRange?: {
|
||||
min?: number;
|
||||
max?: number;
|
||||
};
|
||||
spacing?: {
|
||||
type: "percentage" | "fixed";
|
||||
value: number;
|
||||
};
|
||||
numberOfOrders?: number;
|
||||
individualQuantity?: number;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user