Virtual Markets, Part Three: Price Floors (and more!)

In our last article we discussed market fundamentals and reporting strategies centered around the “High-Low spread”. In this article we will investigate price floor mechanics present in Old School Runescape. In-addition to covering reporting strategies, will also cover a range of related topics, including:

  • Opportunity cost as a function of attention
  • The opportunity cost of botting and real-world trading
  • Capital controls and black markets.
  • Profit maximization strategies for game developers
  • … And more!
Disclaimer: This article is strictly academic in-nature and does not constitute financial advice. I have deleted my OSRS accounts and have no stake in any position within the game.

Price Floors

What Are Price Floors?

Price floors are fixed minimum trade values for commodities which are generally created as the result of intervention or policies set by a governing body. Examples in the real world include minimum wages, or minimum crop prices set through agricultural subsidies.

In circumstances where the market equilibrium price is below a target price floor, these policies create market inefficiencies:

  • In the case of minimum wage laws, the quantity of willing workers (supply) will exceed the quantity of willing employers (demand) at the policy’s target wage floor (price). The government restricts demand by criminalizing wages set by employers below the minimum.
  • In the case of agricultural subsidies, the supply of an agricultural product will exceed demand at the minimum price set by a subsidy. The government absorbs supply by purchasing the resulting surplus created by the subsidy.

Why Should We Care About Price Floors?

There are many different market conditions involving price floors which we can monitor, report against, and profit from. Because no market is perfect, and because price fixing creates an otherwise unnatural/irrational market equilibrium, we can capitalize on circumstances where other parties in a market fail to recognize, understand or appreciate a price floor.

Trading strategies involving price floors present a lower risk profile than alternatives at the cost of generally providing poorer returns. While trading on the Bid-Ask (High-Low) spread discussed in our last article presents the risk of an active position dropping in value, trading against price floors effectively hedges against loss, since prices hypothetically are not permitted to fall below the floor. Even in circumstances where a price floor is not perfectly applied by a governing authority and price dips below the floor due to a sudden supply/demand shock, the governing forces responsible for imposing the target price floor will, over-time, cause price to rise back to its target as long as the governing force maintains policy pressure against the market.

Just as real-world economies are subject to price floors, so are virtual economies such as that of Old School Runescape.

Is There Any Evidence of Price Floors in OSRS?

On July 26 2023, the “Desert Treasure II” quest was released, introducing new bosses and items into the game.

Following this release date, a handful of commodities experienced a surge in trade volume along with a drop in price. Some of these commodities included “Rune javelin heads”, “Dragon javelin heads”, “Uncut Ruby”, “Uncut Diamond”, as well as other items.

So, what happened? Following the release of Desert Treasure II, players spent a lot of time engaging with its related content with the intent to obtain new, rare items. The new bosses introduced into the game also happened to routinely drop varying quantities of these four listed items, which had all already existed in-game prior to the release of DT2. As a result, the market faced a sudden and sustained supply shock as players routinely dumped a higher-than-normal quantity of these items onto the Grand Exchange, causing price to drop.

Over-time, this increased supply of items never let-up, with volume trading today at a substantially elevated level than it did prior to the release of DT2. Despite this, prices rebounded, returning to pre-release levels.

Typically when a market is presented with a new equilibrium volume, all else being equal we would expect to also see a lower equilibrium price. In-order for price to remain the same given these conditions, there has to be a force present in a market resulting in the appearance of a price floor.

So, lets take a look at an in-game mechanism possessing the potential to enforce price floors.

Alchemy

What is Alchemy, and How Does it Relate to Price Floors?

Alchemy, or more specifically “High Level Alchemy” is a magic spell available in OSRS allowing players to convert items directly into GP, the in-game currency. The amount of GP a player will receive is determined by a fixed “highalch” value set by the game developers which varies from item to item.

At face value, these conditions present a textbook example of a surplus-absorbing price floor policy, not unlike that of agricultural subsidies in real life. Assuming that players have unlimited capacity to convert items into GP, the “highalch” value effectively reflects the price floor for each item in the game.

How is Alchemy Inefficient?

Like corn subsidies, alchemy is not a perfectly efficient mechanism, and “highalch” values do not represent perfect price floors. In-order to gauge the true efficacy of alchemy in the context of setting price floors, we need to evaluate any mechanics which may adversely impact the opportunity cost of using the spell relative to other activities players may engage in:

A character must have a magic level of 55 in-order to use the “High Level Alchemy” spell: Most people who are familiar with OSRS consider level 55 magic to be a very “early-game” milestone. As a result, this level requirement on its own does not significantly hamper the impact a mechanism like alchemy would have on setting price floors.

Each use of the spell consumes one “Nature Rune”: This restriction on the other hand is quite significant. At the time of this writing, nature runes cost 170GP each. This immutable “fee” effectively shifts the potential price floor for all in-game items by this amount, completely removing price floors for all items with a “highalch” value of 170GP or less. (*there is an in-game item which modifies the rate of consumption of nature runes, however the effect is so marginal and its break-even point is so high that it isn’t worth factoring into this analysis) (there is also a “ring” which allows players to perform 30 casts of high-level alchemy per day without consuming nature runes, however this is an extremely niche and negligible exception)

The spell can only be cast once every 3 seconds: This restriction is also very significant, as it imposes a rate limit; in-order for players to engage with a potential price floor via alchemy, they must use a non-negligible amount of their time. This has the effect of reducing the opportunity cost of alchemy, eroding its efficacy at enforcing price floors since players will forego alchemy if alternative activities present better opportunity cost. This becomes especially poignant, since more efficient/profitable magic training methods become available to use once a player’s character has reached certain in-game milestones, rendering alchemy a potentially useless substitute activity for some players.

So, it is clear that alchemy is somewhat hampered in its efficacy at enforcing price floors due to its governing mechanics, to the extent that the fixed costs associated with nature runes will cause some items to have no price floor, and also to the extent that rational players will stop to consider opportunity cost before using alchemy.

How is Alchemy Efficient?

While we could stop here and discard alchemy as junk science (in the context of price floors) there are some qualities which Alchemy possesses in OSRS which may increase its opportunity cost and bolster its function as a price floor enforcement mechanism:

Using the spell allows players to free-up inventory slots while engaging with other content in OSRS: While this is an important game mechanic, it has an extremely limited context and use-case. While a player on a combat-related task might use the spell a few dozen times over the span of many hours in-order to convert low-value “drops” into GP, casts which fall under this use-case represent a rounding error against the totality of all alchemy spells cast in the game.

Usage of the spell provides a player’s character with “magic experience” which slowly advances their magic level: This is true of many activities within the game, and is a bit of a moot point until we consider that alchemy is a “0-time” training method which can be cast whilst performing other in-game tasks.

While there are more efficient and profitable methods of training magic in OSRS, Alchemy is the only method which can be *practically trained in-tandem with other disparate skills and activities. These conditions extend the relevance of alchemy for most players far into their play-through, effectively raising the opportunity cost of alchemy versus other spells which cannot be performed in-tandem with other tasks. This is distinct from the inventory-clearing behavior mentioned earlier, as players who deliberately “0-time” alchemy will carry bank notes or other “stackable” or “noted” items to use with the spell, which mitigates inventory management concerns. (*there are of course going to be niche exceptions, however alchemy is the most universal 0-time magic training method)

While this is great at mitigating the otherwise diminishing relevancy of alchemy for veteran players, the opportunity cost of alchemy is still significantly impacted by its slow cast rate. So, how else can Alchemy provide greater opportunity cost?

If a player’s client is configured correctly, the spell can be cast by simply mashing left-click without otherwise meaningfully engaging with the game at all, for potentially hours or days at a time: How does this seemingly preposterous feature increase the opportunity cost of alchemy? In-order to understand why, we need to stop paying attention.

Opportunity Cost as a Function of Attention

Attention Calibration

Time is our most valuable resource. As much as Old School Runescape is a game, it is also a sandbox of endless opportunity cost exercises. Players benefit by maximally leveraging their available time and by engaging with the game’s content in as efficient a manner as possible.

However, this doesn’t present the entire story; different activities within the game present varying degrees of required attention. In a video essay presented by the Youtuber Marstead, the concept of attention calibration is introduced starting at around the 2:54 mark. Essentially, the degree of a player’s attention required to play the game varies wildly between different activities. On one extreme there are activities requiring near-100% of a player’s attention, while on the opposite extreme there are activities which only require that a player left-click once every five minutes.

This concept of attention calibration adds a completely new dimension to all opportunity cost considerations, to the extent that many otherwise inefficient strategies might actually be maximally efficient when factoring-in a given player’s desired attention span. While activities calibrated for higher attention spans typically provide a greater return on investment for a player’s time, activities calibrated for lower attention spans provide a greater return on investment for a player’s attention.

How Attention Calibration Impacts Alchemy

In the context of Alchemy, since players can decide to mindlessly button-mash the spell, the majority of their attention can be allocated toward other tasks or activities in their life. As a result, alchemy is not only maximally efficient as a function of time in the context of “0-time” training, it is also maximally efficient as a function of attention in the context of button-mashing.

Since Alchemy is uniquely efficient for players of all attention spans including high-attention “sweaty” players and low-attention “AFK” players, the opportunity cost of alchemy is increased, strengthening its potential as a price floor enforcement mechanism.

Unfortunately this still doesn’t address the opportunity cost of alchemy with regard to its cast rate limit. All players, regardless of their level of attention, are limited to 1 cast every 3 seconds. As we’ll discuss, some players have embraced an effective, albeit rule-breaking solution to this problem.

Botting

Disclaimer: I do not endorse or condone breaking the rules of Old School Runescape.

What is Botting?

If time is our most valuable resource, the sole purpose of technology is to maximize the utility of time. Thus, if a task can be performed by a machine, automation is a rational consideration.

In the context of OSRS, the use of technology to automate in-game activity is referred to as “botting” and includes the use of scripts, programs, macros, and other tools to effectively “play” the game with limited human interaction.

How Prevalent is Botting in OSRS?

Despite the fact that it is explicitly against the established rules of the game, botting has been a ubiquitous component of OSRS for the entirety of its history, and as with real-world trading, we cannot understand the market of OSRS without also understanding the prevalence, incentives, and context behind botting activity.

Jagex as recently as February 22nd 2024 has posted statistics concerning the prevalence of botting in OSRS. In this article, they claim that over 67,000 accounts are banned from OSRS every week for botting. There are Youtube channels including SirPugger which focus on documenting and recording evidence of botting activity in the game. Practically anybody who has played OSRS has likely encountered bots in one form or another.

How Does Botting Change Opportunity Cost?

So far, we have approached Alchemy and its opportunity costs under the assumption that it is being performed by human players. Even though most players abide by the rules of the game, the opportunity cost of all activities in the game are necessarily impacted by the presence of bots, since they coexist within the same economy. As a result, we must take into account the opportunity costs associated with botting in-order to fully understand alchemy and its impact on price floors.

Let’s start by creating a fanciful hypothetical scenario where botting is free, perfect, and legal.

In this hypothetical scenario, even the lowest-attention activities such as button mashing are made infinitely more efficient when delegated to a machine rather than to a human. Likewise, despite the fact that Alchemy is still rate-limited to one cast every 3 seconds, this rate limit turns into a multiplicative function when we consider the potential of parallelization; by botting with multiple game accounts simultaneously, our rate of alchemy effectively becomes unlimited, rendering the cast rate limit a moot point. Since bots can operate within this framework with no human interaction and can also exceed the attention and multitasking capacities of humans, opportunity cost of alchemy via botting approaches infinity.

The result of legal, fully-automated perfect alchemy is the creation of perfect price floors set at the “alchvalue” for each corresponding item in the game, subtracted by fixed costs (the cost of a nature rune).

While this hypothetical scenario helps to validate the logical extreme that botting presents against the opportunity cost of alchemy, we’ll need to break-down these fanciful assumptions in-order to better approximate the true impact that botting has on alchemy, and on the economy of OSRS as a whole.

Botting is (Not) Free

Any implementation of automation requires the use of resources that we could otherwise use to simply complete the target task; thus, botting is not free.

However in the context of alchemy, implementation might as well be free. A button-mashing macro is one of the oldest tricks in the book. You would be hard pressed to find any modern operating system that doesn’t have this functionality baked-in. While it certainly takes a lot of time and effort automating some of the more complex tasks and activities present in OSRS, automating alchemy easily possesses the lowest barrier to entry.

What about other automation costs, like computer hardware? Wouldn’t it cost a lot of money to host a massive bot farm?

While there certainly are costs, OSRS is built on a 20 year-old game engine that originally ran in a web browser. Any modern computer could run dozens, if not over a hundred separate instances of the game concurrently. Yes, there are fixed and variable costs to consider in the context of operating a large bot farm, however within the confines of this model these costs are fairly negligible.

So, if the costs of writing a botting script are negligible, and if the costs of operating a bot farm are also negligible, what costs aren’t negligible? We need to look no further than the revenue stream of the game publishers themselves to find the greatest cost of automation: Membership.

Players must pay to have access to the full OSRS game experience. While there are “free-to-play” servers available to use, these lack a majority of the items and features present in the full version of the game. While alchemy is technically available to free-to-play players, they are severely limited in the scope of items they can turn into GP. This means that a bot farm operator must purchase membership for each account that they wish to bot with.

So, how do botters obtain membership? Historically, players have obtained membership through a conventional subscription-based payment model. In recent years, the game publishers introduced Old School Bonds or simply Bonds which provide a sanctioned mechanism for players to purchase GP with real-world currency. When a player purchases a bond from Jagex, they can sell the bond on the Grand Exchange for GP. A player purchasing a bond with GP can then convert the bond into 14 days worth of membership for their account.

This mechanism effectively allows bot operators to pay the operating costs of their bot farm using the in-game GP that they earn from their botting operations, pocketing the surplus as profit.

So, how do Bond mechanics in the context of botting change the opportunity cost of alchemy, and its price floor setting potential? While this certainly reduces the opportunity cost of alchemy versus our earlier hypothetical, it provides us with an extremely important variable we can use to better approximate the real price floor. The market value of a bond represents a fixed cost of performing alchemy for a single account within a 14-day window.

So, let’s do some math. An account can perform 1 cast every 3 seconds, which translates to 1200 casts per hour, 28,800 casts per day, or 403,200 casts per 14-day bond window. If we divide the bond cost of 11M GP by the number of casts possible within this 14-day window, we are provided with a per-item break-even margin of 27GP. Adding the cost of a nature rune, this figure becomes 197GP per cast.

While this brings us one step closer toward approximating the true opportunity cost of alchemy, we’ll need to continue breaking-down our original hypothetical to arrive closer to the truth.

Botting is (Not) Perfect

Human-made systems of automation cannot be perfect; they will always contain bugs, and it is impossible to account for every possible fault type. These problems necessitate human interaction to correct.

That said, botting in OSRS at a technical level is pretty close to perfect. In the same news article addressing bot banning, out of all of the accounts banned for botting every week, 2,800 are banned for boss-related activity. For some context, boss-related content is some of the most technically challenging content in the game. Botting accounts frequently top the “hi-scores” list in-terms of kill count, and there is ample footage and documentation of bots engaging in near-flawless PvP, which is considered some of the most technically difficult content in the game.

Botting is (Not) Legal

While bots are practically perfect in their execution of in-game tasks, they are not perfect at evading detection mechanisms. Botting is against the rules of the game and Jagex punishes botters by banning their accounts, resulting in the forfeiture of any remaining membership time and any GP or other assets held by the botting account.

If there is zero enforcement, the opportunity cost of botting is only limited by bond costs. If enforcement is perfect, botting would have zero opportunity cost and cease to exist altogether. Like in real-life, the efficacy of laws is seldom absolute, but is instead a function of enforcement and punishment. We know that Jagex enforces their rules to at least some degree, but we also know that botting remains a pervasive force in the game, so the answer we are looking for lies somewhere in the middle.

We can get a little bit closer to the truth by introducing a few more macroeconomic concepts.

Capital Controls and the Black Market

Capital Controls

As we discussed earlier, Old School Bonds allow players to use real-world currency to effectively purchase in-game GP. The reverse transaction on the other hand is expressly forbidden; Jagex will not give you US Dollars in-exchange for GP, nor are you permitted to real-world trade; that is, to obtain US Dollars from other players in-exchange for your GP. Likewise, when a player buys a bond with GP in-game, this comes at the expense of another player’s fiat. This is a textbook example of a closed capital control policy, not unlike those used by a handful of real-world governments.

Runescape as a Job

While most people play OSRS to have fun, a lot of people play OSRS to make money. For people seeking to use OSRS as a source of revenue via real-world trading, botting presents an attractive means of maximizing opportunity cost, and thus real-world profit.

The incentive structures for bot farm operators are on a level completely alien to that of a regular player. A regular player might never consider breaking game rules, since this comes at the risk of having their account banned. On the flipside, since a real-world trader’s sole goal is to generate profit, and since violating capital controls is already a capital offense within the scope of the game, a real-world trader faces no risk of cumulative penalty when additional rules are broken. As a result, they might as well use botting techniques and leverage the improved opportunity costs, so long as the increased risk of detection is adequately taken into account.

So, how do people who treat OSRS as a job bypass the capital controls enforced by Jagex? Laws are again only as effective as their enforcement and punishment; people who use OSRS as a source of real-world revenue will turn to black markets in-order to exchange their GP for real-world currency, in much the same way that black markets will appear in countries which possess imperfectly enforced capital controls or fixed exchange rates.

Sanctioned versus Unsanctioned Exchange Rates

Since capital controls result in the creation of both a sanctioned and unsanctioned market for GP, how do their exchange rates compare?

Let’s start with the exchange rate sanctioned by Jagex through their sale of bonds. At the time of this writing, an Old School Bond costs $7.99. At a bond value of 11M GP, the exchange rate is $0.72 per 1M GP.

How about black markets? While black market prices are more difficult to accurately gauge, by roughly aggregating information from various listings, the exchange rate currently appears to be about $0.23 per 1M GP.

So, it is clear that GP trades at a significant discount on the black market when compared with the sanctioned market. This makes sense given that the official channel will be used by risk-adverse players who do not want to risk an account ban when purchasing GP, while black markets will be used by less risk-adverse players who prefer a discounted rate.

Calculating our Price Floor

The difference between these exchange rates reveals the “middle ground” we are looking for in our opportunity cost puzzle. We now know that, due to the enforcement risks associated with botting and real-world trading, every 1 GP earned by a rule-breaking player is worth the same as 0.32 GP earned by a rule-abiding player. We obtain this figure by dividing the black market exchange rate with the sanctioned bond rate: 0.23/0.72 = 0.32.

This ratio can be multiplied by the 14-day max cast count calculated earlier in-order to obtain an effective cast rate taking into account enforcement risk. 403,200 * 0.32 = 129,024. By dividing the cost of a 11M bond by this figure, we get 85GP as our break-even point per-cast, or 255GP when including the cost of a nature rune.

This figure makes some intuitive sense in the context of Jagex anti-botting enforcement. An account which performs alchemy at the theoretical maximum rate is going to look extremely suspicious and will be easily caught by even rudimentary anti-bot heuristics, because it is impossible for a human being to repeatedly click for 24 hours a day, 7 days a week. On the other hand, an account performing alchemy at 1/3 of this rate, or, 8 hours a day, is far more plausible for a human to perform, providing a better barometer to adjust botting activity against in-order to balance risk and reward.

So, we finally have our price floor formula:

highalch – Nature Rune Price – (Bond Price / (403,200 * (Black Market Exchange Rate / Jagex Exchange Rate)))

Let’s get started with our reporting!

*Note: This price floor formula has been revised: See adddendum at the end of the article for more details.

Reporting Against the Price Floor

What are our Reporting Goals?

With a price floor now defined, our goal is to take advantage of circumstances where other market actors fail to recognize that a floor exists. Our reporting should inform us when an item’s price has dipped below its price floor, effectively signaling when it should be purchased. Once price has rebounded, we can sell it back to the market, taking the difference minus taxes as profit.

Getting the Black Market Exchange Rate

The scripts shared in the previous article contain all of the data we need to get started reporting, with the exception of two variables: The cost (in USD) of an Old School Bond, and the Black Market Exchange Rate.

For now, we’ll hard-code the USD bond price ($7.99) into our formulas. Jagex is pretty good at telegraphing when price changes occur, and this shouldn’t be too difficult to manually maintain. On the flipside, while it would be easy to hard-code the black market exchange rate into our formulas, this figure is subject to day-to-day fluctuations and should ideally be dynamically updated.

The OSRS Wiki API does not provide black market exchange rates for GP, so we will have to obtain this data from other sources. Using Beautiful Soup and some regex, we can pretty easily scrape price data from various GP-selling websites and use the average as our value. While I’ve included a template for performing this in my OSRSBuildDatabase.py script, I’m not including specific details for the sites I collect data from for at least three or four different reasons. I’ve limited my scraping to once per day, which should provide enough recency for our purposes while being infrequent enough to not result in my IP getting banned by their webmasters.

Building a Report

Using our report generation script as a template, let’s see how our formula looks when translated into SQLite:

...
cur.execute('''CREATE TABLE JagexExchangeRate AS SELECT ((WeeklyMeanLow + WeeklyMeanHigh) / 2) AS BondPrice, CAST((7.99 * 1000000) / ((WeeklyMeanLow + WeeklyMeanHigh) / 2) AS REAL) AS JagexExchangeRate FROM MasterTable WHERE id=13190;''')
cur.execute('''CREATE TABLE NatureRunePrice AS SELECT (GranularDailyMeanLow + GranularDailyMeanHigh) / 2 AS NatureRunePrice FROM MasterTable WHERE id=561;''')
cur.execute('''CREATE TABLE PriceFloor AS SELECT id, MasterTable.mappinghighalch - NatureRunePrice.NatureRunePrice - (JagexExchangeRate.BondPrice / (403200 * (MasterTable.BlackMarketRate / JagexExchangeRate.JagexExchangeRate))) AS PriceFloor FROM MasterTable, NatureRunePrice, JagexExchangeRate;''')

print(pd.read_sql('''SELECT * FROM PriceFloor;''', tempdb))
  • Our first query creates the “JagexExchangeRate” table, containing weekly average Old School Bond prices, as well as the “USD-to-1M GP” exchange rate available via the purchase of bonds.
  • Our next query creates the “NatureRunePrice” table, containing daily average Nature Rune prices.
  • Our final query creates a “PriceFloor” table, using the formula we defined earlier to calculate the price floor for all ids.

We use Weekly Average prices for bonds and Daily Average prices for nature runes in these calculations; this most-closely reflects the fixed sunk costs incurred by any bot or player engaging in alchemy, with bonds being purchased less frequently than nature runes.

The printed result looks like this:

         id     PriceFloor
0         2    -245.010491
1         6  112251.989509
2         8  112251.989509
3        10  112251.989509
4        12  112251.989509
...     ...            ...
4037  28561    -247.010491
4038  22613  179751.989509
4039  22610  179751.989509
4040  28585    -247.010491
4041  22647  179751.989509

If we check each corresponding id, the Price Floor makes sense; in the case of id 2, “Cannonball”, the highalch value is only 3GP, resulting in a negative price floor. Other items likewise have PriceFloor values which are aligned with their highalch values. So far so good!

With our PriceFloor value now ready, let’s apply what we learned during our High-Low spread exercise from our previous article:

...
cur.execute('''CREATE TABLE MasterTableTax AS SELECT * FROM MasterTable INNER JOIN PriceFloor ON MasterTable.id = PriceFloor.id;''')
cur.execute('''ALTER TABLE MasterTableTax ADD COLUMN Tax;''')
cur.execute('''CREATE TABLE MaxTax AS SELECT * FROM MasterTableTax WHERE round(PriceFloor) > 500000000;''')
cur.execute('''CREATE TABLE MinTax AS SELECT * FROM MasterTableTax WHERE round(PriceFloor) <= 500000000;''')
cur.execute('''UPDATE MaxTax SET Tax = 5000000;''')
cur.execute('''UPDATE MinTax SET Tax = round((PriceFloor * 0.01) - 0.5);''')
cur.execute('''CREATE TABLE DailyCSVwithTax AS SELECT * FROM MaxTax UNION SELECT * FROM MinTax;''')
cur.execute('''CREATE TABLE NoBuyLimit AS SELECT *, ((PriceFloor - low - Tax) * 24 * MIN(GranularDailyMeanVolumeLow, GranularDailyMeanVolumeHigh)) AS NoBuyLimitProfit FROM DailyCSVwithTax;''')
cur.execute('''CREATE TABLE WithBuyLimit AS SELECT id, ((PriceFloor - low - Tax) * mappinglimit) AS WithBuyLimitProfit FROM DailyCSVwithTax;''')
cur.execute('''CREATE TABLE DailyCSVwithProfit AS SELECT *, MIN(NoBuyLimit.NoBuyLimitProfit, COALESCE(WithBuyLimit.WithBuyLimitProfit, 'NONE')) AS AdjustedPotentialDailyProfit FROM NoBuyLimit, WithBuyLimit WHERE NoBuyLimit.id = WithBuyLimit.id;''')
cur.execute('''CREATE TABLE FinalOutput AS SELECT mappingname, low, mappinglimit, (PriceFloor - low) AS ProfitPerUnit, ((PriceFloor - low - Tax) / low) * 100 AS ROI FROM DailyCSVwithProfit ORDER BY AdjustedPotentialDailyProfit DESC;''')

print(pd.read_sql('''SELECT * FROM FinalOutput;''', tempdb))

These are largely the same commands used in our last article to calculate taxes, potential profit, volume, and ROI for the High-Low spread, however we have made a few tweaks in-order to suit our new use case involving price floors:

  • Our PriceFloor values are first incorporated into our working table via an INNER JOIN on matching ids.
  • When trading against price floors, it is better to look at real-time data provided by the /latest endpoint since price history has little bearing on the present value of a potential trade. As a result, calculations for taxes, potential profit and ROI now use combinations of an item’s current price floor and the current “low” price, with the latter representing our target price for purchasing a good to trade, and the former representing our target price for selling said good, with the difference sans taxes returned as profit.
  • While it may be more strategically advantageous for more patient traders to price their sell offers higher than the price floor, our calculation should only take into account price floor when calculating returns since this represents our approximate “guaranteed” return on investment.

Our results appear very promising; our top five items include “Fire battlestaff”, “Combat bracelet”, “Onyx bolts (e)”, “Magic longbow”, and “Earth battlestaff”. These items feature:

  • Per-unit potential profit ranging from 80-200GP
  • Favorably high trade volume
  • Favorably high buy limits (10k+ per 4 hour window)
  • In one case (Magic Longbow), high ROI of ~8%
  • “low” prices trending lower than historical averages, setting a precedent for quick returns.

As we see with this example, and as we’ll continue to see in upcoming articles, the market fundamentals we covered in our last article involving taxes, potential profit, volume, and ROI are applicable to virtually all trading strategies. As a result, what we see here is already pretty great; when it comes to fundamental market principles, there is very little we need to change between different trading strategies.

That said, as we encountered during our last reporting exercise, this report contains a lot of potentially bad data which we need to identify and filter-out.

As we work our way down the list, some items appear to provide much greater ROI than others, with two examples including “Rolling Pin” and “Red spiky vambraces”:

Both of these items present great examples of price dips; while they have seemingly stable equilibrium prices, their recent prices have been forced downward by a supply-side shock, breaching their respective price floors. We will cover the mechanics behind this particular phenomenon in our next article; for now, these do not present any obvious signs of behavior we should filter-out of the report we are developing, with the exception of the very low volume reported by “Rolling pin”.

As we go a bit further down the list, we will encounter some items reporting high ROI, high per-item return, and high daily volume. One such example is “Blue d’hide body”:

There is a problem with this item. Despite the price currently trending quite a bit below the price floor, this trending price actually appears to be the item’s market equilibrium price. This would seemingly violate the intuition behind a price floor, until we factor-in the broader impact of buy limits.

Our reporting already factors buy limits into calculating potential profit; items with low buy limits fall further down our list because a single player is limited in the quantity that they can trade. So, it makes sense that “Blue d’hide body”, with a buy limit of only 125 per 4-hour window ranks lower than other items with higher buy limits. While this clearly impacts the profit potential for traders, it also impacts the opportunity cost presented to anybody wishing to perform alchemy.

The ideal alchemy cast rate given current $/GP exchange rates is 129024 per 14-day window. This means that an efficient account will perform 1536 alchemy casts per 4-hour buy limit window. This means that an account can only fulfill about 8% of its alchemy potential by purchasing this item alone. Since we’ve established that alchemy is a mechanism for setting price floors, low buy limits will degrade an item’s opportunity cost of alchemy, reducing its efficacy at setting price floors consistent with our formula.

While it is possible to perform alchemy against a set of disparate items, the attention needed to accomplish this comes at a non-negligible cost; players must either spend more of their time micro-managing both their inventory and buy orders on the Grand Exchange, or spend more capital if they take a hands-off approach and maintain large buy orders for an extended duration, accumulating useful quantities of low buy limit items over-time. While this diminishes opportunity costs for rule-abiding players, this impact is multiplied in the case of botting; this added complication turns what would otherwise be an extremely simple auto-clicking macro with low barriers to entry into a somewhat more complicated, capital-intensive, and risky operation. While it might be trivial for a seasoned bot developer to achieve this result, these efforts would be better delegated toward other far-more lucrative tasks present in the game; alchemy is, in the grand scheme of OSRS, a low-attention, low-reward activity. Thus, the added complexity that items with low buy limits present for effective alchemy reduces opportunity cost, which is reflected in the lower equilibrium price for low buy-limit items.

While it might be possible to improve our formula by attempting to accurately calculate price floors for items possessing low buy limits, our reporting already rightfully suggests that items with low buy limits present limited profit potential. As a result, rather than modify our formula, we will simply exclude items which possess a buy limit below a reasonable threshold. While this comes at the cost of excluding some potentially profitable items such as “Rolling pin” and “Red spiky vambraces” from our report no matter how far they dip in price, items like these will be better served by the “price dip” reporting strategy which we will work on developing in our next article.

So, let’s add a WHERE clause to our query, eliminating items where our efficient cast rate exceeds buy limit:

...cur.execute('''CREATE TABLE FinalOutput AS SELECT mappingname AS ItemName, low AS LowPrice, PriceFloor, mappinglimit AS BuyLimit, (PriceFloor - low - Tax) AS ProfitPerUnit, ((PriceFloor - low - Tax) / low) * 100 AS pctROI FROM DailyCSVwithProfit, JagexExchangeRate WHERE mappinglimit > (4800 * (BlackMarketRate) / (JagexExchangeRate.JagexExchangeRate)) AND (GranularDailyMeanVolumeHigh + GranularDailyMeanVolumeLow) / 2 > 4800 * (BlackMarketRate) / (JagexExchangeRate.JagexExchangeRate) AND pctROI > 1 ORDER BY AdjustedPotentialDailyProfit DESC;''')

In-addition to filtering for buy limit, we’ve added two more clauses:

  • Our second clause eliminates items with low daily trade volume; just as low buy limits reduce opportunity cost, so does limited volume irregardless of buy limit. Before adding this clause, items such as “Mithril limbs” appeared in our report; despite featuring a buy limit of 10,000 every four hours, this item would be lucky to see that much movement in volume after four months. It isn’t worth keeping items like this in our report given our intended trading strategy.
  • Our third clause eliminates items with extremely low ROI (1% or less). While trading against price floors typically already provides low ROI, by enforcing this limit we can help ensure that items only appear on our report if they have a decent probability of providing worthwhile returns. This also helps round-off any margin of error which may be present in our price floor formula. Before adding this clause, a handful of high-volume items (elemental battlestaves) appeared, each reporting an ROI of less than 1%. Upon closer inspection, while these items do see their “High” values occasionally float up to our estimated price floor, in the longer-term they have been trending at prices slightly lower than the price floor, but slightly higher than the reported price.

Our resulting report returns 13 items; after cross-referencing each with the OSRS Wiki Prices website, they all appear to be solid choices; each item is appropriately undervalued when compared with their respective price floors, and they all report current prices lower than trending averages, making them all excellent candidates for purchasing at the current low, below the price floor, to be re-sold against or above the price floor.

Like our High-Low spread report, this Alchemy report has been published on my Projects page, and is configured to automatically refresh every minute with new data.

Other Comments and Observations

Missing Items

When introducing the concept of price floors and presenting evidence for their existence, I specifically referenced four items. These included “Rune javelin heads”, “Dragon javelin heads”, “Uncut Ruby” and “Uncut Diamond”.

If you keep tabs on the published report, you may encounter the first two items, however in virtually no circumstance will “Uncut Ruby” or “Uncut Diamond” ever appear on this report. Both of these items feature extremely low highalch values. Despite this, they share almost the exact same price histories as the javelin heads in the context of the release of the DT2 quest. Why is this?

Uncut gems represent raw, or unfinished goods. If you look at the report long enough, items including “Diamond Necklace” or “Ruby Bracelet” might appear; these are finished products, each possessing a much higher “highalch” value than their individual components. The market value of an uncut gem closely resembles, but does not exactly mirror the highalch value of its finished products.

While it is possible to build reporting against raw or intermediate goods in the context of price floors, this is a bit more complicated and prone to error since many crafting recipes require multiple inputs to create a single output, necessitating the creation and use of recipe tables. The resulting price floors are also noticeably “softer” since changes in price for one ingredient will impact the prices for other ingredients. While I don’t currently plan to further discuss or report against raw/intermediate goods in the context of price floors, we will investigate a specific trading strategy involving the use of recipe tables in the fifth article in this series.

The Curious Case of Bonds

While writing this article, I started to recognize that Old School Bonds are extremely peculiar items. This peculiarity is best illustrated when we consider their relation to both rule-abiding and rule-breaking players.

When a rule-breaking player purchases a bond using GP they obtained through botting, Jagex is effectively selling illicitly-generated GP to players in-exchange for fiat currency. This is compounded by the fact that Jagex enforces strict capital controls; they don’t refund fiat currency to players who may have received “illicit” GP through the sale of bonds on the Grand Exchange.

Since bonds represent a revenue source for Jagex, and since bots require membership provided by bonds in-order to operate, there is a clear incentive for Jagex to imperfectly enforce their rules against botting. This becomes clear when we consider a scenario of perfect rule enforcement.

If botting rules were perfectly enforced:

  • Bots wouldn’t buy and consume bonds, reflecting a net reduction in bond demand
  • As demand decreases, bond price (in GP) will go down
  • Lower bond price (in GP) raises the $/GP exchange rate; the same dollars provide fewer GP
  • Higher $/GP exchange rate results in players exchanging less $ to generate new bonds.
  • Reduction in supply of bonds results in new equilibrium, with supply and demand both lower than if botting rules were not perfectly enforced.

So, without a doubt, Jagex absolutely benefits from real-world trading being prevalent in Old School Runescape. That isn’t to say that they selectively enforce rules, however given that Jagex is owned by a private equity fund, we shouldn’t leave all options off of the table. A “rational Jagex” interested in maximizing profit would embrace botting to the extent that it does not adversely impact player goodwill, or participation in their sanctioned market for GP by risk-adverse players wanting GP, or real-world traders wanting bonds to sustain membership.

Another funny bond mechanic involves the impact real-world traders purchasing bonds has against their own bottom-line on the black market. When a botter buys a bond for GP, the GP value of bonds rises. Thus, the sanctioned exchange rate between $ and GP drops, becoming more favorable to players seeking to purchase GP with fiat directly from Jagex. This behavior ironically works against real-world traders, since reducing the sanctioned exchange rate, all else being equal, makes the sanctioned rate more favorable for players wishing to exchange fiat for GP. In a sense, as much as membership is a fee for service for legitimate players, it also serves as a tax and mitigating force against rule-breaking activity.

Whether or not botters decide to continue operating is dependent on the value of the surplus of their gains, beyond the fixed costs presented by a bond. If Jagex rule enforcement is so draconian that botters cannot even cover the cost of a bond, they’ll disappear from the game entirely and, as we determined earlier, net Jagex a loss. On the flipside, if there is little/no enforcement, the surplus GP landing on the black market will become saturated, resulting in an extremely low, and extremely attractive black market exchange rate as uninhibited bots flood the market. If the sanctioned rate becomes so unattractive compared with the black market that nobody is purchasing bonds with fiat, the bots themselves fall into jeopardy since their operations require membership provided through bonds in-order to operate. The end-result is that, bots themselves actually benefit from some degree of rule enforcement, since the fiat provided by players purchasing GP at the sanctioned exchange rate effectively covers the majority of their fixed costs of botting.

Assuming that Jagex is in fact a rational actor in this market, it makes the most sense for them to strike a balance with regard to real-world trading activity, permitting real-world traders and botters to operate at a limited capacity.

Inflation

Real-world traders and botting also present a mechanism for driving inflation. Since botting has greater opportunity cost than abiding by game rules, bots will more effectively generate GP than regular players. Since a botter has no interest in holding onto GP, this GP lands in the hands of other players via sanctioned and black markets. This necessarily increases money supply, creating a scenario where a greater amount of money is chasing after the same amount of goods, creating inflation.

Inflation, while annoying for most players trying to progress through the game, presents an enticing proposition for Jagex; inflation forces players to play the game longer. The most veteran players want the most effective and expensive equipment. Individual pieces of “best-in-slot” equipment often costs hundreds of millions, if not billions of GP each. The inflation generated through botting causes the prices of the most expensive items in the game to continue to rise as more money enters the market, widening the chasm between “mid-game” players and “late-game” content.

This problem is exacerbated further when we consider the fundamental purpose of all Grand Exchange taxes: Funding an Item Sink. When players pay taxes, this money is pooled and used to destroy some of the rarest items in the game, reducing the supply of super-rare items within an otherwise inflationary market. This can easily equate to players spending further months, if not years playing the game in-order to obtain the best gear…

… Or they can skip this grind by buying bonds!

Conclusion

I hope this article has been insightful; this one was a lot of fun to research and write. I will be discussing and reporting against the OSRS market phenomenon of “price dips” in our next article, so please stay tuned for more analysis and scripting examples!

Thank you for reading!

*Note: “Virtual Markets, Part Four: Shocks and Dip Detection” is now live!

March 10 2024 Addendum

Since publishing this article, I’ve been tracking the associated report and have noticed that the reported price floors seem to be trending higher than recent market prices. For some items, the reported price floors even match or exceed historic max values. This appears to be due to a combination of two different factors:

Nature Rune Price Activity

Nature runes represent an important fixed cost for alchemy. In recent history the price activity for this item has been volatile, to say the least:

To summarize, the price of nature runes sat at an equilibrium of about 90GP each for the majority of the past year before rising to a peak of about 190GP, falling back down to where it is today at 125GP.

This volatility has an interesting impact on our price floor calculations, as well as the price behavior for items typically used for alchemy. We can see this quite clearly by checking historic trends for “Diamond Necklace”:

This impact is even more pronounced when looking at the cheaper “Ruby Necklace”:

There are two things that these price histories infer:

  • Nature runes, representing a fixed cost of alchemy, have an inverse price relationship with items used for alchemy. Changes in nature rune prices thus result in an inverse and proportional price floor change. This behavior is consistent with our price floor formula.
  • … However, a change in nature rune price does not immediately impact the price of items used for alchemy; there is a time delay. We see this both in the span between November – December 2023 where brief spikes in nature rune prices had no noticeable downward impact on necklace price, and again in early March 2023 where a dip in nature rune prices had not (yet) caused necklace prices to rise.

While the interplay between nature rune price and other item prices plays a large role in our seemingly inflated price floor calculations, there is another factor to consider:

Missing Costs for Alchemy

Even after factoring the time delay of nature rune price changes, our price floor formula still tends to over-estimate the “true” price floor. This is especially prevalent for relatively expensive items, such as elemental battlestaves. Right now, our reported price floor for Water, Earth, Air and Fire battlestaves is 9094GP, however this price has only been encountered on the market a very small handful of times in the past year. This is in sharp contrast with less expensive items such as “Magic longbow” which report a price floor of 1330GP, with this price being very typical for this item within the past year.

So, why are we getting this over-estimation, and why is it impacting expensive items more than cheaper items? Right now, our price floor formula takes into account the fixed costs of bonds, nature runes, and rule enforcement. What it fails to take into account is the opportunity cost of capital (GP) for the person (or bot) performing alchemy.

While 1330GP and 9094GP both represent fairly minuscule values in the greater context of the game, if we consider the quantity of items needed to perform alchemy efficiently without needing to repeatedly use the Grand Exchange to restock, the difference in initial capital investment between these two items is over 10 million GP. In the context of a bot farm operator, this is capital that could instead be distributed to additional bots and, given our knowledge about enforcement risks, a botter risks more capital when they perform alchemy on more expensive items due to the nullification of assets when a ban occurs.

While our reporting does take taxes into account, somebody performing alchemy does not know or care how much we spent on taxes buying and “flipping” an item; all else being equal, just as traders prefer to spend less capital investing in positions, an alchemy caster prefers the same.

So, how do we modify our price floor to take the opportunity cost of GP for alchemy casters into account? The most direct way would be to incorporate the GE tax calculation directly into the price floor formula, providing a linear adjustment as a function of an item’s price. if we consider the adjustment in the context of elemental battlestaves, we see our adjusted price floor drop to 9004GP. This price is substantially more appropriate and within the realm of normal trading history for these specific items, while otherwise not significantly impacting the price floor for less-expensive items.

To incorporate this change, I’ve modified the body of the report generation script, with the change to our formula highlighted in bold:

cur.execute('''CREATE TABLE JagexExchangeRate AS SELECT ((WeeklyMeanLow + WeeklyMeanHigh) / 2) AS BondPrice, CAST((7.99 * 1000000) / ((WeeklyMeanLow + WeeklyMeanHigh) / 2) AS REAL) AS JagexExchangeRate FROM MasterTable WHERE id=13190;''')
cur.execute('''CREATE TABLE NatureRunePrice AS SELECT (GranularDailyMeanLow + GranularDailyMeanHigh) / 2 AS NatureRunePrice FROM MasterTable WHERE id=561;''')
cur.execute('''CREATE TABLE PriceFloor AS SELECT id, round(((MasterTable.mappinghighalch - NatureRunePrice.NatureRunePrice - (JagexExchangeRate.BondPrice / (403200 * (MasterTable.BlackMarketRate / JagexExchangeRate.JagexExchangeRate)))) * 0.99) + 0.5) AS PriceFloor FROM MasterTable, NatureRunePrice, JagexExchangeRate;''')
cur.execute('''CREATE TABLE MasterTableTax AS SELECT * FROM MasterTable INNER JOIN PriceFloor ON MasterTable.id = PriceFloor.id;''')
cur.execute('''ALTER TABLE MasterTableTax ADD COLUMN Tax;''')
cur.execute('''UPDATE MasterTableTax SET Tax = round((PriceFloor * 0.01) - 0.5);''')
cur.execute('''CREATE TABLE NoBuyLimit AS SELECT *, ((PriceFloor - low - Tax) * 24 * MIN(GranularDailyMeanVolumeLow, GranularDailyMeanVolumeHigh)) AS NoBuyLimitProfit FROM MasterTableTax;''')
cur.execute('''CREATE TABLE WithBuyLimit AS SELECT id, ((PriceFloor - low - Tax) * mappinglimit) AS WithBuyLimitProfit FROM MasterTableTax;''')
cur.execute('''CREATE TABLE DailyCSVwithProfit AS SELECT *, MIN(NoBuyLimit.NoBuyLimitProfit, COALESCE(WithBuyLimit.WithBuyLimitProfit, 'NONE')) AS AdjustedPotentialDailyProfit FROM NoBuyLimit, WithBuyLimit WHERE NoBuyLimit.id = WithBuyLimit.id;''')
cur.execute('''CREATE TABLE FinalOutput AS SELECT mappingname AS ItemName, low AS LowPrice, PriceFloor, mappinglimit AS BuyLimit, (PriceFloor - low - Tax) AS ProfitPerUnit, ((PriceFloor - low - Tax) / low) * 100 AS pctROI FROM DailyCSVwithProfit, JagexExchangeRate WHERE mappinglimit > (4800 * (BlackMarketRate) / (JagexExchangeRate.JagexExchangeRate)) AND (GranularDailyMeanVolumeHigh + GranularDailyMeanVolumeLow) / 2 > 4800 * (BlackMarketRate) / (JagexExchangeRate.JagexExchangeRate) AND pctROI > 1 ORDER BY AdjustedPotentialDailyProfit DESC;''')

This change adjusts our price floor calculation so that it is discounted by its associated tax value before any further calculations are made. We don’t need to incorporate the 5M tax limit logic here, since there are no items in the game with a highalch value anywhere near 500M and I’ve further removed these steps from the remaining report logic.

With this change, our price floors provide a much better representation of the market, with the historic market values for all reported items frequently intersecting the floor. My published report will reflect these changes; while I don’t anticipate any further modifications being necessary, I’ll be keeping tabs on this report to ensure there are no other missing factors that need to be considered.