Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
120 changes: 120 additions & 0 deletions examples/data-api-positions.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
<?php

declare(strict_types=1);

require_once __DIR__.'/../vendor/autoload.php';

use Danielgnh\PolymarketPhp\Client;

/**
* Example: Fetching user positions and analytics from Data API.
*
* This example demonstrates how to use the Data API to:
* - Get current (open) positions for a user
* - Get closed positions (historical)
* - Calculate total position value
* - Get trade history
* - Get on-chain activity
* - Get market analytics (holders, open interest, volume)
* - Get leaderboard data
*/

// Initialize client (no authentication needed for Data API)
$client = new Client();

// Example wallet address
$walletAddress = '0x0000000000000000000000000000000000000000';

echo "Data API Examples\n";
echo "=================\n\n";

// 1. Get current (open) positions
try {
echo "1. Fetching current positions...\n";
$positions = $client->data()->positions()->get($walletAddress);
echo 'Found '.count($positions)." open positions\n\n";
} catch (Exception $e) {
echo "Error: {$e->getMessage()}\n\n";
}

// 2. Get closed positions
try {
echo "2. Fetching closed positions...\n";
$closedPositions = $client->data()->positions()->closed($walletAddress);
echo 'Found '.count($closedPositions)." closed positions\n\n";
} catch (Exception $e) {
echo "Error: {$e->getMessage()}\n\n";
}

// 3. Get total position value
try {
echo "3. Calculating total position value...\n";
$value = $client->data()->positions()->value($walletAddress);
echo "Total value: \${$value['total']}\n\n";
Copy link

Copilot AI Jan 24, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The code assumes that the API response contains a 'total' key without checking its existence first. While the try-catch block will handle exceptions, for consistency with other example files in this codebase (such as examples/bridge-deposit.php which uses isset() checks), consider adding a check before accessing the key, or use the null coalescing operator. For example: echo "Total value: $" . ($value['total'] ?? '0') . "\n\n";

Suggested change
echo "Total value: \${$value['total']}\n\n";
echo "Total value: $" . ($value['total'] ?? '0') . "\n\n";

Copilot uses AI. Check for mistakes.
} catch (Exception $e) {
echo "Error: {$e->getMessage()}\n\n";
}

// 4. Get trade history
try {
echo "4. Fetching trade history...\n";
$trades = $client->data()->trades()->get($walletAddress, ['limit' => 10]);
echo 'Found '.count($trades)." recent trades\n\n";
} catch (Exception $e) {
echo "Error: {$e->getMessage()}\n\n";
}

// 5. Get on-chain activity
try {
echo "5. Fetching on-chain activity...\n";
$activity = $client->data()->activity()->get($walletAddress, ['limit' => 10]);
echo 'Found '.count($activity)." activity records\n\n";
} catch (Exception $e) {
echo "Error: {$e->getMessage()}\n\n";
}

// 6. Get market analytics (example condition ID)
$conditionId = '0x0000000000000000000000000000000000000000000000000000000000000000';

try {
echo "6. Fetching market holders...\n";
$holders = $client->data()->analytics()->holders($conditionId, ['limit' => 5]);
echo 'Found '.count($holders)." top holders\n\n";
} catch (Exception $e) {
echo "Error: {$e->getMessage()}\n\n";
}

try {
echo "7. Fetching open interest...\n";
$openInterest = $client->data()->analytics()->openInterest($conditionId);
echo "Open interest data retrieved\n\n";
} catch (Exception $e) {
echo "Error: {$e->getMessage()}\n\n";
}

// 8. Get leaderboard
try {
echo "8. Fetching leaderboard...\n";
$leaderboard = $client->data()->leaderboards()->get(['limit' => 10]);
echo 'Found '.count($leaderboard)." top traders\n\n";
} catch (Exception $e) {
echo "Error: {$e->getMessage()}\n\n";
}

// 9. Get builder leaderboard
try {
echo "9. Fetching builder leaderboard...\n";
$builderLeaderboard = $client->data()->leaderboards()->builder(['limit' => 10]);
echo 'Found '.count($builderLeaderboard)." builders\n\n";
} catch (Exception $e) {
echo "Error: {$e->getMessage()}\n\n";
}

// 10. Check API health
try {
echo "10. Checking Data API health...\n";
$health = $client->data()->health()->check();
echo "Status: {$health['status']}\n";
Copy link

Copilot AI Jan 24, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The code assumes that the API response contains a 'status' key without checking its existence first. While the try-catch block will handle exceptions, for consistency with other example files in this codebase (such as examples/bridge-deposit.php which uses isset() checks), consider adding a check before accessing the key, or use the null coalescing operator. For example: echo "Status: " . ($health['status'] ?? 'unknown') . "\n";

Suggested change
echo "Status: {$health['status']}\n";
echo "Status: " . ($health['status'] ?? 'unknown') . "\n";

Copilot uses AI. Check for mistakes.
} catch (Exception $e) {
echo "Error: {$e->getMessage()}\n";
}
18 changes: 17 additions & 1 deletion src/Client.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ class Client

private ?Bridge $bridgeClient = null;

private ?Data $dataClient = null;

private ?ClobAuthenticator $clobAuthenticator = null;

/**
Expand All @@ -30,7 +32,8 @@ public function __construct(
array $options = [],
?HttpClientInterface $gammaHttpClient = null,
?HttpClientInterface $clobHttpClient = null,
?HttpClientInterface $bridgeHttpClient = null
?HttpClientInterface $bridgeHttpClient = null,
?HttpClientInterface $dataHttpClient = null
) {
$this->config = new Config($apiKey, $options);

Expand All @@ -45,6 +48,10 @@ public function __construct(
if ($bridgeHttpClient instanceof HttpClientInterface) {
$this->bridgeClient = new Bridge($this->config, $bridgeHttpClient);
}

if ($dataHttpClient instanceof HttpClientInterface) {
$this->dataClient = new Data($this->config, $dataHttpClient);
}
}

/**
Expand Down Expand Up @@ -115,4 +122,13 @@ public function bridge(): Bridge

return $this->bridgeClient;
}

Copy link

Copilot AI Jan 24, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The data() method is missing a docblock comment. For consistency with other API client accessor methods in this class (gamma(), clob(), and bridge()), this method should have a docblock describing what it returns. Consider adding a docblock similar to the one used for bridge() method.

Suggested change
/**
* Get Data API client for market and trading data.
*
* @return Data
*/

Copilot uses AI. Check for mistakes.
public function data(): Data
{
if (!$this->dataClient instanceof Data) {
$this->dataClient = new Data($this->config);
}

return $this->dataClient;
}
}
3 changes: 3 additions & 0 deletions src/Config.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ class Config

public readonly string $bridgeBaseUrl;

public readonly string $dataBaseUrl;

public readonly ?string $apiKey;

public readonly int $timeout;
Expand All @@ -34,6 +36,7 @@ public function __construct(?string $apiKey = null, array $options = [])
$this->gammaBaseUrl = is_string($options['gamma_base_url'] ?? null) ? $options['gamma_base_url'] : 'https://gamma-api.polymarket.com';
$this->clobBaseUrl = is_string($options['clob_base_url'] ?? null) ? $options['clob_base_url'] : 'https://clob.polymarket.com';
$this->bridgeBaseUrl = is_string($options['bridge_base_url'] ?? null) ? $options['bridge_base_url'] : 'https://bridge-api.polymarket.com';
$this->dataBaseUrl = is_string($options['data_base_url'] ?? null) ? $options['data_base_url'] : 'https://data-api.polymarket.com';
$this->timeout = is_int($options['timeout'] ?? null) ? $options['timeout'] : 30;
$this->retries = is_int($options['retries'] ?? null) ? $options['retries'] : 3;
$this->verifySSL = is_bool($options['verify_ssl'] ?? null) ? $options['verify_ssl'] : true;
Expand Down
69 changes: 69 additions & 0 deletions src/Data.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
<?php

declare(strict_types=1);

namespace Danielgnh\PolymarketPhp;

use Danielgnh\PolymarketPhp\Http\GuzzleHttpClient;
use Danielgnh\PolymarketPhp\Http\HttpClientInterface;
use Danielgnh\PolymarketPhp\Resources\Data\Activity;
use Danielgnh\PolymarketPhp\Resources\Data\Analytics;
use Danielgnh\PolymarketPhp\Resources\Data\Health;
use Danielgnh\PolymarketPhp\Resources\Data\Leaderboards;
use Danielgnh\PolymarketPhp\Resources\Data\Positions;
use Danielgnh\PolymarketPhp\Resources\Data\Trades;

/**
* Data API Client.
*
* Handles all Data API operations (positions, trades, analytics, leaderboards).
* https://data-api.polymarket.com
*
* Resources:
* - Health: API health check
* - Positions: Current and closed positions
* - Trades: Trade history and activity
Copy link

Copilot AI Jan 24, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The class docblock lists the available resources but omits the Activity resource. For completeness, add "Activity: On-chain operations including trades, splits, merges, redemptions" to the resources list in the docblock (around line 25), similar to how other resources are documented.

Suggested change
* - Trades: Trade history and activity
* - Trades: Trade history and activity
* - Activity: On-chain operations including trades, splits, merges, redemptions

Copilot uses AI. Check for mistakes.
* - Analytics: Market analytics, volume, open interest
* - Leaderboards: Trader and builder rankings
*/
class Data
{
private readonly HttpClientInterface $httpClient;

public function __construct(
private readonly Config $config,
?HttpClientInterface $httpClient = null
) {
$this->httpClient = $httpClient ?? new GuzzleHttpClient($this->config->dataBaseUrl, $this->config);
}

public function health(): Health
{
return new Health($this->httpClient);
}

public function positions(): Positions
{
return new Positions($this->httpClient);
}

public function trades(): Trades
{
return new Trades($this->httpClient);
}

public function activity(): Activity
{
return new Activity($this->httpClient);
}

public function analytics(): Analytics
{
return new Analytics($this->httpClient);
}

public function leaderboards(): Leaderboards
{
return new Leaderboards($this->httpClient);
}
}
32 changes: 32 additions & 0 deletions src/Resources/Data/Activity.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<?php

declare(strict_types=1);

namespace Danielgnh\PolymarketPhp\Resources\Data;

use Danielgnh\PolymarketPhp\Exceptions\PolymarketException;
use Danielgnh\PolymarketPhp\Resources\Resource;

class Activity extends Resource
{
/**
* Get on-chain operations including trades, splits, merges, redemptions, rewards, and conversions.
*
* @param string $user User wallet address
* @param array<string, mixed> $filters Additional filters (type, limit, offset, etc.)
*
* @return array<int, array<string, mixed>>
*
* @throws PolymarketException
*/
public function get(string $user, array $filters = []): array
{
$response = $this->httpClient->get('/activity', [
'user' => $user,
...$filters,
]);

/** @var array<int, array<string, mixed>> */
return $response->json();
}
}
68 changes: 68 additions & 0 deletions src/Resources/Data/Analytics.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
<?php

declare(strict_types=1);

namespace Danielgnh\PolymarketPhp\Resources\Data;

use Danielgnh\PolymarketPhp\Exceptions\PolymarketException;
use Danielgnh\PolymarketPhp\Resources\Resource;

class Analytics extends Resource
{
/**
* Get top token holders per market.
*
* @param string $conditionId Market condition ID
* @param array<string, mixed> $filters Additional filters (limit, offset, etc.)
*
* @return array<int, array<string, mixed>>
*
* @throws PolymarketException
*/
public function holders(string $conditionId, array $filters = []): array
{
$response = $this->httpClient->get('/holders', [
'condition_id' => $conditionId,
...$filters,
]);

/** @var array<int, array<string, mixed>> */
return $response->json();
}

/**
* Get total value of outstanding positions in a market.
*
* @param string $conditionId Market condition ID
* @param array<string, mixed> $filters Additional filters
*
* @return array<string, mixed>
*
* @throws PolymarketException
*/
public function openInterest(string $conditionId, array $filters = []): array
{
$response = $this->httpClient->get('/open-interest', [
'condition_id' => $conditionId,
...$filters,
]);

return $response->json();
}

/**
* Track trading volume with per-market breakdown.
*
* @param array<string, mixed> $filters Filters (conditionId, startDate, endDate, etc.)
*
* @return array<string, mixed>
*
* @throws PolymarketException
*/
public function liveVolume(array $filters = []): array
{
$response = $this->httpClient->get('/live-volume', $filters);

return $response->json();
}
}
25 changes: 25 additions & 0 deletions src/Resources/Data/Health.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<?php

declare(strict_types=1);

namespace Danielgnh\PolymarketPhp\Resources\Data;

use Danielgnh\PolymarketPhp\Exceptions\PolymarketException;
use Danielgnh\PolymarketPhp\Resources\Resource;

class Health extends Resource
{
/**
* Check Data API operational status.
*
* @return array<string, mixed>
*
* @throws PolymarketException
*/
public function check(): array
{
$response = $this->httpClient->get('/health');

return $response->json();
}
}
Loading