Conversation with Gemini
import requests
import json
from datetime import datetime, timedelta, timezone
# Configuration
API_KEY = "1d9fc73c-11be-4d53-a098-a7b6915d252a"
ENDPOINT = "[Link]
PUMPSWAP_PROGRAM =
"pAMMBay6oceH9fJKBRHGP5D4bD4sWpmSwMn52FMfXEA"
# 1. Using timezone-aware UTC for the since parameter
yesterday = ([Link]([Link]) -
timedelta(hours=24)).strftime('%Y-%m-%dT%H:%M:%SZ')
# 2. Query including $offset and $limit variables as requested
query = """
query GetNewPumpSwapPools($since: DateTime, $limit: Int, $offset:
Int) {
Solana(dataset: realtime) {
Instructions(
where: {
Instruction: {
Program: {
Address: {is: "%s"},
Method: {is: "create_pool"}
}
},
Transaction: {Result: {Success: true}},
Block: {Time: {since: $since}}
}
limit: {count: $limit, offset: $offset}
orderBy: {descending: Block_Time}
){
Block {
Time
}
Transaction {
Signature
}
Instruction {
Accounts {
Address
}
}
}
}
}
""" % PUMPSWAP_PROGRAM
def fetch_and_save_to_json(total_to_fetch=1000, batch_size=100):
headers = {
"Content-Type": "application/json",
"X-API-KEY": API_KEY
}
# This list will store EVERY instruction detail retrieved
all_data_storage = []
current_offset = 0
print(f"Starting fetch for up to {total_to_fetch} records via
pagination...")
while len(all_data_storage) < total_to_fetch:
payload = {
"query": query,
"variables": {
"since": yesterday,
"limit": batch_size,
"offset": current_offset
}
}
response = [Link](ENDPOINT, json=payload,
headers=headers)
if response.status_code == 200:
data = [Link]()
if 'errors' in data:
print(f"GraphQL Error at offset {current_offset}:",
data['errors'][0]['message'])
break
instructions = [Link]('data', {}).get('Solana',
{}).get('Instructions')
if not instructions:
print(f"No more records found at offset {current_offset}.
Finalizing file...")
break
# Store the raw instruction batch into our storage list
all_data_storage.extend(instructions)
print(f"Captured {len(all_data_storage)} instructions...")
# Increment offset for pagination
current_offset += batch_size
else:
print(f"HTTP Error: {response.status_code},
{[Link]}")
break
# --- SAVE EVERYTHING TO JSON FILE ---
filename = "all_pumpswap_instructions.json"
with open(filename, "w", encoding="utf-8") as f:
[Link](all_data_storage, f, indent=4)
print(f"\n--- COMPLETED ---")
print(f"Total instructions captured: {len(all_data_storage)}")
print(f"Everything has been saved to: {filename}")
if __name__ == "__main__":
fetch_and_save_to_json(total_to_fetch=1000)
i saw a part where there isdescending, if replaced with ascending,
what will e the differnece between the two and willthe result be
different?
The short answer is yes, the results will be significantly
different, especially in the context of how your pagination logic
interacts with the Bitquery timeline.
Here is the breakdown of how changing descending to ascending
affects your script:
1. The Timeline Direction
descending (Current): You are fetching the most recent pools
first. If a pool was created 1 minute ago, it appears at the top. As
you increase the offset, you travel "back in time" toward the 24-
hour mark you set in your since variable.
ascending (Changed): You will fetch the oldest pools first
(starting from exactly 24 hours ago). If a pool was created 23 hours
and 59 minutes ago, it appears first. As you increase the offset,
you travel "forward in time" toward the current moment.
2. Impact on "New" Data
If you are running this script to find the "latest" tokens to trade or
track:
With Descending: You get the freshest data immediately. If the
script hits a rate limit or you stop it early, you still have the most
relevant (newest) entries.
With Ascending: You have to finish the entire loop of 1,000
records to finally see what happened in the last 10 minutes. The
first 100 results will be pools that are already nearly a day old.
3. Logic Differences
There is a technical nuance regarding how limit and offset work
with time-series data:
Feature descending (Block_Time) ascending (Block_Time)
First The very last pool created on The first pool created after
Result Solana. your since timestamp.
Paginatio Moves from New → Old. Moves from Old → New.
n
Data If new pools are created while the Generally more stable for
Gaps script runs, they might shift the historical exports.
offset positions.
Summary Table
Query Result Order Use Case
Variable
descending 2:00 PM, 1:55 Real-time monitoring, sniping, or getting
PM, 1:50 PM... the "latest" 1000 pools.
ascending Yesterday 2:00 Historical analysis, backtesting, or
PM, 2:05 PM... building a database from a specific start
point.
Verdict: If your goal is to see what is launching now, keep it as
descending. If you change it to ascending, your JSON file will be
filled with "stale" pools from yesterday first.
Traceback (most recent call last):
File "C:\Users\Oluwabukunmi\AppData\Local\Programs\Python\
Python312\Lib\site-packages\urllib3\[Link]", line 789, in
urlopen
response = self._make_request(
^^^^^^^^^^^^^^^^^^^
File "C:\Users\Oluwabukunmi\AppData\Local\Programs\Python\
Python312\Lib\site-packages\urllib3\[Link]", line 490, in
_make_request
raise new_e
File "C:\Users\Oluwabukunmi\AppData\Local\Programs\Python\
Python312\Lib\site-packages\urllib3\[Link]", line 466, in
_make_request
self._validate_conn(conn)
File "C:\Users\Oluwabukunmi\AppData\Local\Programs\Python\
Python312\Lib\site-packages\urllib3\[Link]", line 1095,
in _validate_conn
[Link]()
File "C:\Users\Oluwabukunmi\AppData\Local\Programs\Python\
Python312\Lib\site-packages\urllib3\[Link]", line 730, in
connect
sock_and_verified = _ssl_wrap_socket_and_match_hostname(
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\Users\Oluwabukunmi\AppData\Local\Programs\Python\
Python312\Lib\site-packages\urllib3\[Link]", line 909, in
_ssl_wrap_socket_and_match_hostname
ssl_sock = ssl_wrap_socket(
^^^^^^^^^^^^^^^^
File "C:\Users\Oluwabukunmi\AppData\Local\Programs\Python\
Python312\Lib\site-packages\urllib3\util\ssl_.py", line 469, in
ssl_wrap_socket
ssl_sock = _ssl_wrap_socket_impl(sock, context, tls_in_tls,
server_hostname)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\Users\Oluwabukunmi\AppData\Local\Programs\Python\
Python312\Lib\site-packages\urllib3\util\ssl_.py", line 513, in
_ssl_wrap_socket_impl
return ssl_context.wrap_socket(sock,
server_hostname=server_hostname)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
^^^^^^^^^^^^^^^^^^^^^
File "C:\Users\Oluwabukunmi\AppData\Local\Programs\Python\
Python312\Lib\[Link]", line 455, in wrap_socket
return self.sslsocket_class._create(
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\Users\Oluwabukunmi\AppData\Local\Programs\Python\
Python312\Lib\[Link]", line 1041, in _create
self.do_handshake()
File "C:\Users\Oluwabukunmi\AppData\Local\Programs\Python\
Python312\Lib\[Link]", line 1319, in do_handshake
self._sslobj.do_handshake()
ConnectionResetError: [WinError 10054] An existing connection was
forcibly closed by the remote host
During handling of the above exception, another exception
occurred:
Traceback (most recent call last):
File "C:\Users\Oluwabukunmi\AppData\Local\Programs\Python\
Python312\Lib\site-packages\requests\[Link]", line 667, in
send
resp = [Link](
^^^^^^^^^^^^^
File "C:\Users\Oluwabukunmi\AppData\Local\Programs\Python\
Python312\Lib\site-packages\urllib3\[Link]", line 843, in
urlopen
retries = [Link](
^^^^^^^^^^^^^^^^^^
File "C:\Users\Oluwabukunmi\AppData\Local\Programs\Python\
Python312\Lib\site-packages\urllib3\util\[Link]", line 474, in
increment
raise reraise(type(error), error, _stacktrace)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\Users\Oluwabukunmi\AppData\Local\Programs\Python\
Python312\Lib\site-packages\urllib3\util\[Link]", line 38, in reraise
raise value.with_traceback(tb)
File "C:\Users\Oluwabukunmi\AppData\Local\Programs\Python\
Python312\Lib\site-packages\urllib3\[Link]", line 789, in
urlopen
response = self._make_request(
^^^^^^^^^^^^^^^^^^^
File "C:\Users\Oluwabukunmi\AppData\Local\Programs\Python\
Python312\Lib\site-packages\urllib3\[Link]", line 490, in
_make_request
raise new_e
File "C:\Users\Oluwabukunmi\AppData\Local\Programs\Python\
Python312\Lib\site-packages\urllib3\[Link]", line 466, in
_make_request
self._validate_conn(conn)
File "C:\Users\Oluwabukunmi\AppData\Local\Programs\Python\
Python312\Lib\site-packages\urllib3\[Link]", line 1095,
in _validate_conn
[Link]()
File "C:\Users\Oluwabukunmi\AppData\Local\Programs\Python\
Python312\Lib\site-packages\urllib3\[Link]", line 730, in
connect
sock_and_verified = _ssl_wrap_socket_and_match_hostname(
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\Users\Oluwabukunmi\AppData\Local\Programs\Python\
Python312\Lib\site-packages\urllib3\[Link]", line 909, in
_ssl_wrap_socket_and_match_hostname
ssl_sock = ssl_wrap_socket(
^^^^^^^^^^^^^^^^
File "C:\Users\Oluwabukunmi\AppData\Local\Programs\Python\
Python312\Lib\site-packages\urllib3\util\ssl_.py", line 469, in
ssl_wrap_socket
ssl_sock = _ssl_wrap_socket_impl(sock, context, tls_in_tls,
server_hostname)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\Users\Oluwabukunmi\AppData\Local\Programs\Python\
Python312\Lib\site-packages\urllib3\util\ssl_.py", line 513, in
_ssl_wrap_socket_impl
return ssl_context.wrap_socket(sock,
server_hostname=server_hostname)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
^^^^^^^^^^^^^^^^^^^^^
File "C:\Users\Oluwabukunmi\AppData\Local\Programs\Python\
Python312\Lib\[Link]", line 455, in wrap_socket
return self.sslsocket_class._create(
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\Users\Oluwabukunmi\AppData\Local\Programs\Python\
Python312\Lib\[Link]", line 1041, in _create
self.do_handshake()
File "C:\Users\Oluwabukunmi\AppData\Local\Programs\Python\
Python312\Lib\[Link]", line 1319, in do_handshake
self._sslobj.do_handshake()
[Link]: ('Connection aborted.',
ConnectionResetError(10054, 'An existing connection was forcibly
closed by the remote host', None, 10054, None))
During handling of the above exception, another exception
occurred:
Traceback (most recent call last):
File "c:\Users\Oluwabukunmi\Downloads\[Link]", line 28,
in <module>
response = [Link](URL, headers=headers,
params=params)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
^^^^^^^^
File "C:\Users\Oluwabukunmi\AppData\Local\Programs\Python\
Python312\Lib\site-packages\requests\[Link]", line 73, in get
return request("get", url, params=params, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
^^^
File "C:\Users\Oluwabukunmi\AppData\Local\Programs\Python\
Python312\Lib\site-packages\requests\[Link]", line 59, in request
return [Link](method=method, url=url, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
^^^^^^^^
File "C:\Users\Oluwabukunmi\AppData\Local\Programs\Python\
Python312\Lib\site-packages\requests\[Link]", line 589, in
request
resp = [Link](prep, **send_kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\Users\Oluwabukunmi\AppData\Local\Programs\Python\
Python312\Lib\site-packages\requests\[Link]", line 703, in
send
r = [Link](request, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\Users\Oluwabukunmi\AppData\Local\Programs\Python\
Python312\Lib\site-packages\requests\[Link]", line 682, in
send
raise ConnectionError(err, request=request)
[Link]: ('Connection aborted.',
ConnectionResetError(10054, 'An existing connection was forcibly
closed by the remote host', None, 10054, None))
PS C:\Users\Oluwabukunmi\Downloads\dragon\Dragon-main>
wa6 does ths mean
That error, ConnectionResetError: [WinError 10054], is
basically the server’s way of hanging up the phone on you mid-
conversation.
It means your script tried to talk to the API, but the connection was
"forcibly closed" by the remote host (Bitquery or Moralis) before the
data could be sent back.
Why is this happening?
There are three likely culprits for this:
1.
Rate Limiting / "Aggressive" Fetching: If your script sends too
many requests too fast (especially with that while loop pagination),
the server might think you're a bot (or a DDoS attack) and kill the
connection to protect itself.
2.
3.
Unstable Network: Since you're on a Windows machine,
sometimes a flickering Wi-Fi connection or a local firewall/antivirus
can reset the socket connection.
4.
5.
Server Overhead: If you are requesting a huge amount of data in
one batch (e.g., a batch_size of 100 on a heavy GraphQL query),
the server might time out and drop the connection.
6.
How to Fix It
1. Add "Breathing Room" (Timeouts & Sleeps)
Don't hammer the API in a tight loop. Import time and add a small
delay between requests. This is the most common fix for 10054.
Python
import time
# Inside your while loop:
response = [Link](ENDPOINT, json=payload, headers=headers,
timeout=30)# ... after processing data ...
[Link](1) # Wait 1 second before the next page
2. Use a Session with Retries
Instead of calling [Link]() directly, use a Session object.
This allows Python to reuse the same connection, which is much
more stable.
Python
from [Link] import HTTPAdapterfrom [Link] import
Retry
session = [Link]()
retries = Retry(total=5, backoff_factor=1, status_forcelist=[502, 503,
504])
[Link]('[Link] HTTPAdapter(max_retries=retries))
# Then use:
response = [Link](ENDPOINT, json=payload, headers=headers)
3. Lower the Batch Size
If you are pulling 100 records at once and the server is struggling,
try lowering batch_size to 50 or 25. It will take more requests to
get to 1,000, but each request is "lighter" and less likely to be cut
off.
4. Check your API Key/Plan
Ensure you haven't hit your daily point limit on Bitquery. Some APIs
will reset the connection rather than sending a polite "429 Too Many
Requests" error if your quota is completely exhausted.
Quick test: Try running the script again in 5 minutes. If it works for
a few pages and then crashes again, it’s definitely a rate-limiting
issue.
import requests
from datetime import datetime, timedelta, timezone
API_KEY =
"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJub25jZSI6ImMzNTQ0NTQ
2LTZkYjgtNGYyMS1hMWJjLTNlMWE1OThkYTdiMiIsIm9yZ0lkIjoiNTE1O
TE5IiwidXNlcklkIjoiNTMwOTYwIiwidHlwZUlkIjoiNTFkMGZiM2MtZWUy
My00MjYwLThjNTctOGQzNjU0ZmNjNzY5IiwidHlwZSI6IlBST0pFQ1QiL
CJpYXQiOjE3Nzg3MTUzNDEsImV4cCI6NDkzNDQ3NTM0MX0.6Mgb3n
kN6DraEQvwFQUE89oIrYMZGX29gW-9278cy14"
URL =
"[Link]
n/graduated"
headers = {
"X-Api-Key": API_KEY
}
now = [Link]([Link])
last_24h = now - timedelta(hours=24)
graduated_tokens = set() # use set to avoid duplicates
cursor = None
while True:
params = {
"limit": 100
}
if cursor:
params["cursor"] = cursor
response = [Link](URL, headers=headers,
params=params)
response.raise_for_status()
data = [Link]()
#print(data)
for token in [Link]("result", []):
created_at = [Link]("createdAt")
if not created_at:
continue
try:
created_time = [Link](
created_at.replace("Z", "+00:00")
)
# only last 24 hours
if created_time >= last_24h:
token_address = [Link]("tokenAddress")
if token_address:
graduated_tokens.add(token_address)
except Exception:
continue
# move cursor forward
cursor = [Link]("cursor")
# stop if no more pages
if not cursor:
break
# print only token addresses
#for addr in graduated_tokens:
# print(addr)
print(graduated_tokens)
print("\nTotal graduated tokens (last 24h):", len(graduated_tokens))
this code, whats the order of fetching the tokens being fetched
Based on the logic of your script and the way the Moralis Solana
API (specifically the "[Link] Graduated" endpoint) typically
handles data, the tokens are being fetched in descending
chronological order (Newest to Oldest).
Here is the breakdown of why that is the case and how the flow
works:
1. Newest First (Descending Order)
The Moralis endpoint for graduated tokens returns the most recently
graduated tokens on the first page.
Page 1: Contains the tokens that moved to Raydium/graduated just
a few seconds or minutes ago.
Subsequent Pages: As you use the cursor to move forward, you
are essentially scrolling back in time.
2. The Pagination Flow
Your while True loop follows this pattern:
1.
It requests the first 100 items (the most recent).
2.
3.
It extracts the cursor for the next 100 items.
4.
5.
It continues until your if created_time >= last_24h filter fails
(though currently, your script iterates through all available
historical data until the cursor is empty, just choosing not to add
older ones to your set).
6.
3. Processing vs. Storage
While the fetching is chronological, the output in your script might
look random:
Fetching: Order is Token A (12:05), Token B (12:00), Token C
(11:55).
Storage: Because you are using graduated_tokens = set(), the
order is lost once the addresses are stored. Sets in Python are
unordered. If you need to keep them in the order they were found,
you should use a list().
A Note on Efficiency
Currently, your script will keep fetching every single graduated
token ever recorded until it runs out of cursors, even after it passes
the 24-hour mark. To save on API credits and time, you should add a
break once you find tokens older than 24 hours:
Python
# inside your for loopif created_time >= last_24h:
token_address = [Link]("tokenAddress")
if token_address:
graduated_tokens.add(token_address)else:
# Since they are ordered Newest -> Oldest,
# once we hit one older than 24h, the rest will be too.
break
Summary: The API serves them Newest to Oldest, but your use
of a set() makes the final print() appear in a randomized order.
show thismolace that say sits netwest to oldest, c i want to turn it to
oldsest to newest
You're right—it's much better to see them in chronological order if
you're trying to analyze the flow of launches.
The Moralis API (and most Solana indexing APIs) serves data in
descending order by default because most users only care about
the most recent "Top 10" results. Since there isn't a simple
order=ascending toggle for this specific endpoint, you have to
handle it in your Python logic.
Here is the updated code. I have changed three things to make it
work the way you want:
1.
Reversed the order: I changed the graduated_tokens from a set
(which is random) to a list and added [::-1] at the end to flip the
list from oldest to newest.
2.
3.
Optimized the fetch: Added a break so the script stops once it
hits tokens older than 24 hours (saving you time and API credits).
4.
5.
Order preservation: Used a list so the sequence stays exactly how
you retrieved it.
6.
Python
import requestsfrom datetime import datetime, timedelta, timezone
API_KEY = "YOUR_API_KEY"
URL =
"[Link]
un/graduated"
headers = {"X-Api-Key": API_KEY}
now = [Link]([Link])
last_24h = now - timedelta(hours=24)
# 1. We use a list now to keep the order (sets are random)
temp_list = []
cursor = None
print("Fetching tokens (Newest to Oldest)...")
while True:
params = {"limit": 100}
if cursor:
params["cursor"] = cursor
response = [Link](URL, headers=headers, params=params)
response.raise_for_status()
data = [Link]()
batch = [Link]("result", [])
if not batch:
break
reached_end_of_24h = False
for token in batch:
created_at = [Link]("createdAt")
if not created_at: continue
created_time = [Link](created_at.replace("Z",
"+00:00"))
if created_time >= last_24h:
token_address = [Link]("tokenAddress")
if token_address:
temp_list.append(token_address)
else:
# 2. Since API is New -> Old, once we hit a 'too old'
token, we stop entirely
reached_end_of_24h = True
break
if reached_end_of_24h:
break
cursor = [Link]("cursor")
if not cursor:
break
# 3. FLIP THE LIST: This turns Newest->Oldest into Oldest-
>Newest
graduated_tokens = temp_list[::-1]
print("\n--- RESULTS (OLDEST TO NEWEST) ---")for addr in
graduated_tokens:
print(addr)
print(f"\nTotal: {len(graduated_tokens)} tokens found in the
last 24h.")
Why this is better:
The "Flip": The [::-1] syntax tells Python "start at the end and
walk backward to the beginning."
Speed: Because the API gives you the newest ones first, you find
your "24-hour limit" very quickly. My added break prevents the
script from looking at tokens from last week that you don't need.
Logic: It effectively transforms the data stream from [Now, 1hr
ago, 2hr ago] into [24hr ago, 23hr ago, ... Now].
Gemini is AI and can make mistakes.