@@ -23,6 +23,8 @@ import { createArrayCsvWriter } from "csv-writer";
23
23
import {
24
24
OrderSide ,
25
25
OrderConfiguration ,
26
+ Position ,
27
+ PortfolioType ,
26
28
} from "../../advanced-sdk-ts/src/rest/types/common-types" ;
27
29
import { CreateOrderResponse } from "../../advanced-sdk-ts/src/rest/types/orders-types" ;
28
30
@@ -109,18 +111,40 @@ export const pnlProvider: Provider = {
109
111
runtime . getSetting ( "COINBASE_API_KEY" ) ?? process . env . COINBASE_API_KEY ,
110
112
runtime . getSetting ( "COINBASE_PRIVATE_KEY" ) ?? process . env . COINBASE_PRIVATE_KEY
111
113
) ;
112
- const portfolioId = runtime . getSetting ( "COINBASE_PORTFOLIO_ID" ) ?? process . env . COINBASE_PORTFOLIO_ID ;
114
+ const portfolios = JSON . parse ( await client . listPortfolios ( { portfolioType : PortfolioType . DEFAULT } ) ) ;
115
+ elizaLogger . info ( "Portfolios:" , portfolios ) ;
116
+ const portfolioId = portfolios . portfolios [ 0 ] . uuid ;
117
+ elizaLogger . info ( "Portfolio ID:" , portfolioId ) ;
118
+ return { realizedPnl : 0 , unrealizedPnl : 0 } ;
113
119
if ( ! portfolioId ) {
114
120
elizaLogger . error ( "Portfolio ID is not set" ) ;
115
121
return { realizedPnl : 0 , unrealizedPnl : 0 } ;
116
122
}
117
- client . getAccount
118
- const balanceSummary = await client . getPerpetualsPortfolioSummary ( { portfolioUuid : portfolioId } ) ;
119
- const portfolioBalances = balanceSummary ?. summary ;
120
- elizaLogger . info ( "Balance Summary:" , balanceSummary ) ;
121
- const unrealizedPnl = portfolioBalances ?. unrealized_pnl || 0 ;
122
- elizaLogger . info ( "Unrealized PNL:" , unrealizedPnl ) ;
123
- return unrealizedPnl ;
123
+
124
+ let btcPosition : Position , ethPosition : Position ;
125
+ try {
126
+ btcPosition = JSON . parse ( await client . getPortfolioBalances ( { portfolioUuid : portfolioId , symbol : "BTC-USD" } ) ) . position ;
127
+ ethPosition = JSON . parse ( await client . getPortfolioBalances ( { portfolioUuid : portfolioId , symbol : "ETH-USD" } ) ) . position ;
128
+ elizaLogger . info ( "BTC Position:" , btcPosition ) ;
129
+ elizaLogger . info ( "ETH Position:" , ethPosition ) ;
130
+ } catch ( error ) {
131
+ elizaLogger . error ( "Error fetching portfolio balances:" , error . message ) ;
132
+ return { realizedPnl : 0 , unrealizedPnl : 0 } ;
133
+ }
134
+
135
+ const btcUnrealizedPnl = btcPosition ?. unrealized_pnl || 0 ;
136
+ const ethUnrealizedPnl = ethPosition ?. unrealized_pnl || 0 ;
137
+ const ethAggregatedPnl = ethPosition ?. aggregated_pnl || 0 ;
138
+ const btcAggregatedPnl = btcPosition ?. aggregated_pnl || 0 ;
139
+ elizaLogger . info ( "BTC Unrealized PNL:" , JSON . stringify ( btcUnrealizedPnl ) ) ;
140
+ elizaLogger . info ( "ETH Unrealized PNL:" , JSON . stringify ( ethUnrealizedPnl ) ) ;
141
+ elizaLogger . info ( "ETH Aggregated PNL:" , JSON . stringify ( ethAggregatedPnl ) ) ;
142
+ return {
143
+ btcUnrealizedPnl : JSON . stringify ( btcUnrealizedPnl ) ,
144
+ ethUnrealizedPnl : JSON . stringify ( ethUnrealizedPnl ) ,
145
+ ethAggregatedPnl : JSON . stringify ( ethAggregatedPnl ) ,
146
+ btcAggregatedPnl : JSON . stringify ( btcAggregatedPnl )
147
+ }
124
148
}
125
149
}
126
150
@@ -140,8 +164,8 @@ export async function appendTradeToCsv(tradeResult: any) {
140
164
tradeResult . failure_response ?. order_id ||
141
165
"" ,
142
166
tradeResult . success ,
143
- // JSON.stringify(tradeResult.order_configuration || {}),
144
- // JSON.stringify(tradeResult.success_response || tradeResult.failure_response || {})
167
+ JSON . stringify ( tradeResult . order_configuration || { } ) ,
168
+ JSON . stringify ( tradeResult . success_response || tradeResult . failure_response || { } )
145
169
] ;
146
170
147
171
elizaLogger . info ( "Formatted trade for CSV:" , formattedTrade ) ;
@@ -166,7 +190,6 @@ async function hasEnoughBalance(
166
190
try {
167
191
const response = await client . listAccounts ( { } ) ;
168
192
const accounts = JSON . parse ( response ) ;
169
- elizaLogger . info ( "Accounts:" , accounts ) ;
170
193
const checkCurrency = side === "BUY" ? "USD" : currency ;
171
194
elizaLogger . info (
172
195
`Checking balance for ${ side } order of ${ amount } ${ checkCurrency } `
@@ -208,7 +231,25 @@ async function hasEnoughBalance(
208
231
}
209
232
}
210
233
211
- async function getPrice ( client : RESTClient , productId : string ) {
234
+ export async function getPrice ( client : RESTClient , productId : string ) {
235
+ elizaLogger . debug ( "Fetching product info for productId:" , productId ) ;
236
+ try {
237
+ const productInfo = await client . getProduct ( { productId} ) ;
238
+ const price = JSON . parse ( productInfo ) ?. price ;
239
+ elizaLogger . info ( "Product info retrieved:" , productInfo ) ;
240
+ elizaLogger . info ( "Price:" , price ) ;
241
+ return Number ( price ) ;
242
+ } catch ( error ) {
243
+ elizaLogger . error ( "Error fetching product info:" , error ) ;
244
+ return null ;
245
+ }
246
+ }
247
+
248
+ export async function getPricUSD ( runtime : IAgentRuntime , productId : string ) {
249
+ const client = new RESTClient (
250
+ runtime . getSetting ( "COINBASE_API_KEY" ) ?? process . env . COINBASE_API_KEY ,
251
+ runtime . getSetting ( "COINBASE_PRIVATE_KEY" ) ?? process . env . COINBASE_PRIVATE_KEY
252
+ ) ;
212
253
elizaLogger . debug ( "Fetching product info for productId:" , productId ) ;
213
254
try {
214
255
const productInfo = await client . getProduct ( { productId} ) ;
@@ -246,7 +287,7 @@ export const executeAdvancedTradeAction: Action = {
246
287
] ,
247
288
handler : async (
248
289
runtime : IAgentRuntime ,
249
- _message : Memory ,
290
+ message : Memory ,
250
291
state : State ,
251
292
_options : any ,
252
293
callback : HandlerCallback
@@ -276,12 +317,14 @@ export const executeAdvancedTradeAction: Action = {
276
317
277
318
// Generate trade details
278
319
let tradeDetails ;
320
+ const updatedState = state ;
321
+ updatedState . message = message . content . text ;
279
322
elizaLogger . debug ( "Starting trade details generation" ) ;
280
323
try {
281
324
tradeDetails = await generateObject ( {
282
325
runtime,
283
326
context : composeContext ( {
284
- state,
327
+ state : updatedState ,
285
328
template : advancedTradeTemplate ,
286
329
} ) ,
287
330
modelClass : ModelClass . LARGE ,
@@ -316,7 +359,7 @@ export const executeAdvancedTradeAction: Action = {
316
359
let amountInCurrency = amount ;
317
360
// Configure order
318
361
let orderConfiguration : OrderConfiguration ;
319
- elizaLogger . debug ( "Starting order configuration" ) ;
362
+ elizaLogger . debug ( "Starting order configuration" , { productId , amount , side , orderType , limitPrice } ) ;
320
363
try {
321
364
if ( orderType === "MARKET" ) {
322
365
const priceInUSD = await getPrice ( client , productId ) ;
@@ -343,7 +386,7 @@ export const executeAdvancedTradeAction: Action = {
343
386
}
344
387
orderConfiguration = {
345
388
limit_limit_gtc : {
346
- baseSize : amount . toString ( ) ,
389
+ baseSize : amountInCurrency . toString ( ) ,
347
390
limitPrice : limitPrice . toString ( ) ,
348
391
postOnly : false ,
349
392
} ,
@@ -387,23 +430,25 @@ export const executeAdvancedTradeAction: Action = {
387
430
) ;
388
431
return ;
389
432
}
390
-
391
- order = await client . createOrder ( {
392
- clientOrderId : crypto . randomUUID ( ) ,
433
+ const orderId = crypto . randomUUID ( ) ;
434
+ order = JSON . parse ( await client . createOrder ( {
435
+ clientOrderId : orderId ,
393
436
productId,
394
437
side : side === "BUY" ? OrderSide . BUY : OrderSide . SELL ,
395
438
orderConfiguration,
396
- } ) ;
397
-
439
+ } ) ) ;
440
+ elizaLogger . info ( "Order:" , JSON . stringify ( order ) ) ;
398
441
if ( order . success ) {
442
+ elizaLogger . info ( "Trade executed successfully:" , JSON . stringify ( order ) ) ;
399
443
callback (
400
444
{
401
- text : `Trade executed successfully: ${ order . order_id } ` ,
445
+ text : `Trade executed successfully: ${ JSON . stringify ( order ) } ` ,
402
446
} ,
403
447
[ ]
404
448
) ;
405
449
elizaLogger . info ( "Trade executed successfully:" , order ) ;
406
450
} else {
451
+ elizaLogger . error ( "Trade execution failed:" , ( order as any ) ?. error_response ?. message ) ;
407
452
callback (
408
453
{
409
454
text : `Failed to execute trade: ${ ( order as any ) ?. error_response ?. message ?? "Unknown error occurred" } ` ,
@@ -423,7 +468,7 @@ export const executeAdvancedTradeAction: Action = {
423
468
}
424
469
// Log trade to CSV
425
470
try {
426
- // await appendTradeToCsv(order);
471
+ await appendTradeToCsv ( order ) ;
427
472
elizaLogger . info ( "Trade logged to CSV" ) ;
428
473
} catch ( csvError ) {
429
474
elizaLogger . warn ( "Failed to log trade to CSV:" , csvError ) ;
@@ -519,5 +564,5 @@ export const advancedTradePlugin: Plugin = {
519
564
name : "advancedTradePlugin" ,
520
565
description : "Enables advanced trading using Coinbase Advanced Trading API" ,
521
566
actions : [ executeAdvancedTradeAction ] ,
522
- providers : [ tradeProvider ] ,
567
+ providers : [ tradeProvider , pnlProvider ] ,
523
568
} ;
0 commit comments