Guides & Tutorials7 min read

Price Your GPUs From Their Own Demand: A Rental Price That Adjusts Itself

A price set once is wrong most of the time: too high while the machine sits idle, too low when it is re-rented within minutes. Here is a small script on the Paralon provider API that lowers a node's price after hours of idling, raises it when renters queue up, and never leaves the limits you set. With a replay of a week of one RTX 4090 and every decision it made.

-5%
after 6 idle hours on the market, by default
+5%
when re-rented within an hour of the last rental
80% to 150%
of the node's default price: the default limits
A glowing gold line stepping down across a dark wall towards a soft green floor: a price coming down step by step and stopping at its limit

Most GPU hosts set a price once, when they add a machine, and never touch it again. That price is wrong most of the time. While the machine sits idle it is too high: a renter looking at the list picked something cheaper. When the machine is re-rented minutes after the last renter left, it is too low: someone was waiting, and would have paid more.

On Paralon you can now change a node's price from code, through the provider API. This guide uses that to let each node's price follow its own demand, inside limits you choose, so you stop guessing.

The rule

For each node, every 15 minutes:

What happenedWhat the script does
On the market and idle for 6 hours since the last changelowers the price by 5%
Rented again within 1 hour of the previous rental endingraises the price by 5% for the next rental
Anything elsekeeps the price

Two limits wrap the rule. The price never goes below 80% or above 150% of the node's default price (your floor and ceiling, both settable), and never outside what Paralon allows: 50% to 300% of the default, which the API reports per node as price.min and price.max. Spot nodes rent at the spot price and are left alone.

Why the node's own demand and not the market's: it is the signal that belongs to you. Two cards of the same model can rent at different prices because of where they are, their reputation or their uptime record. An idle machine says its price is too high for what it offers; a queue of renters says the opposite.

What you need

  • A Paralon API key with the My nodes permission (Console → API keys).
  • Python 3.8 or newer with requests.

Both scripts are in the auto-pricing/ folder of our open-source provider tools repository (MIT).

The two calls it uses

Read every node, with its state and its price limits:

curl https://paraloncloud.com/api/v1/nodes -H "Authorization: Bearer $PARALON_API_KEY"
"price": { "currency": "USD", "unit": "hour", "spot": false,
           "default": 0.54, "min": 0.27, "max": 1.62,
           "custom": null, "renter_pays": 0.54 }

Set a price (or null to go back to the default):

curl -X PATCH https://paraloncloud.com/api/v1/nodes/$NODE_ID \
  -H "Authorization: Bearer $PARALON_API_KEY" -H "Content-Type: application/json" \
  -d '{"price_per_hour": 0.51}'

The price is what a renter pays per hour for the whole node, in US dollars; you earn it minus the platform fee. A price outside min–max is refused with the range in the message, and a rental already running keeps the price it started at.

The decision, in one function

The API reports a node's current state, not its history, so the script remembers two times per node in a small JSON file: when it became idle, and when its last rental ended. decide() takes the node and that memory and returns the new price, or none:

if state == "rented":
    if prev != "rented":                      # a rental just started
        quick = last_rental_end is not None and now - last_rental_end <= QUICK_HOURS * 3600
        if quick and current < hi:
            return round(min(hi, current * (1 + STEP)), 2)   # renters were waiting
    return None                               # rented: keep

if state == "available":
    idle_h = (now - idle_since) / 3600
    if idle_h >= IDLE_HOURS and current > lo:
        idle_since = now                      # a full IDLE_HOURS before the next step
        return round(max(lo, current * (1 - STEP)), 2)       # nobody wants it at this price

Offline, paused and not-yet-ready nodes are not on the market, so their idle time does not count: a machine that was switched off for a night does not come back cheaper.

A week of one RTX 4090, replayed

simulate.py feeds a made-up week of one node through the same decide() with the defaults, and makes no API call. The node starts at its $0.54 default, sits idle for most of a day, then gets rented in quick succession, then idles again:

h    0  available  $0.54           available, idle 0.0 h: keep
h    6  available  $0.54 -> $0.51  idle 6.0 h: -5%
h   12  available  $0.51 -> $0.48  idle 6.0 h: -5%
h   18  available  $0.48 -> $0.46  idle 6.0 h: -5%
h   19  rented     $0.46           rented: keep
h   31  available  $0.46           available, idle 0.0 h: keep
h 31.5  rented     $0.46 -> $0.48  re-rented within 1 h: +5% for the next rental
h   55  available  $0.48           available, idle 0.0 h: keep
h 55.5  rented     $0.48 -> $0.50  re-rented within 1 h: +5% for the next rental
h   86  available  $0.50 -> $0.47  idle 6.0 h: -5%
h   92  available  $0.47 -> $0.45  idle 6.0 h: -5%
h   98  available  $0.45 -> $0.44  idle 6.0 h: -5%
h  104  available  $0.44           available, idle 6.0 h: keep

Three things to read from it. A day of idling took the price down 15% before a renter took it at $0.46. Two quick re-rentals moved it back up, each change applying to the next rental, never to the one that just started. And at the end the price stopped at $0.44, the floor (80% of $0.54, rounded up to the cent), however long the node keeps idling.

Run it

Always start with a dry run. It reads your nodes and prints what it would do, without changing anything:

pip install requests
export PARALON_API_KEY=prlc_your_key
python3 auto_price.py --dry-run

On our own account, with our RTX 4090 rented and the other machines offline, it decided to touch nothing, which is right (the 4090's line):

21:49:36 4090                 rented       $0.54/h  rented: keep

Then run it for real, as a service (systemd or a restart: unless-stopped container). It checks every 15 minutes, logs every decision with its reason, and keeps its memory in auto_price_state.json next to it:

python3 auto_price.py

The knobs

VariableDefaultWhat it sets
IDLE_HOURS6idle time on the market before a step down
QUICK_HOURS1how soon after a rental a new one counts as demand
STEP0.05size of each change
FLOOR0.8lowest price, as a share of the default
CEILING1.5highest price, as a share of the default
MARKET_JSONnonea file of reference prices per GPU model; the price then stays within MARKET_BAND (15%) of it
CHECK_MINUTES15how often it checks

Keep the steps small and the floor honest. A price that drops fast fills the machine with renters who leave when it goes back up; one that never drops below your electricity cost is the only floor that matters. Count your power at full load: a 4090 drew about 450 W in our measurements.

For a fleet

The script handles every node of the account in one pass: one GET /nodes, and one PATCH only for the nodes whose price changes. Machines with different GPUs get their own default, limits and steps automatically. If you also list machines on another marketplace, run the multi-marketplace watcher next to it: the two never fight, because one changes availability and the other changes the price.

The provider API docs list every field a node returns.

Frequently asked questions

Does changing the price affect a rental that is already running?

No. A rental keeps the price it started with until it ends. A new price applies to the next rental.

What limits does Paralon put on a custom price?

Between 50% and 300% of the default price for the node's GPUs. The API reports both limits for each node (price.min and price.max) and refuses a price outside them. The script adds your own, narrower floor and ceiling inside that range.

Does the script look at other providers' prices?

Not by default: it follows the node's own demand, which is the signal you actually control. If you trust a reference price for a GPU model (yours from another marketplace, for example), put it in MARKET_JSON and the script keeps the price within 15% of it.

Does it work on spot nodes?

No. A spot node always rents at the default price minus the spot discount and takes no custom price, so the script leaves spot nodes alone.

How do I try it without changing anything?

Run it with --dry-run: it reads your nodes and prints what it would do, without a single change. simulate.py replays a made-up week through the same rule and makes no API call at all.

On the network

A GPU with JupyterLab on it, in about a minute

Billed for the minutes it runs, on a machine we benchmarked before listing it. Or call open models through an OpenAI-compatible API.

Keep reading

Related articles