jpcsupplies / Economy_mod

Basic Economy System for Space Engineers
13 stars 12 forks source link

Suggestion? (Reactive pricing to stock) #89

Open Demolish50 opened 8 years ago

Demolish50 commented 8 years ago

Would it be possible to do real time NPC market price changes based on stock?

It's written for readability. I'm not neither as talented as you two but it does work. Something like this: https://github.com/TheEngineer50/SEPowerShellTools/blob/master/marketmaint.ps1

Here is the output of that: https://www.pastee.org/tgttr

I run this during my server maintenance but if somehow it could be done real time. I'm not familiar enough with C# to make it happen.


EDIT BY DEVELOPER:

jpcsupplies commented 8 years ago

We did have auto-restock in one of our later roadmap plans, I was thinking something similar to what you have here; where the server generates "pretend" trades with imaginary traders to maintain stock levels, but the idea of sliding scale prices seems interesting. Converting NPC money into stock would work well where players are doing a lot of buying too, midspace was thinking something similar using NPC trader ships, the price and stock being effected by the success or failure of those ships to arrive and leave the trade base unmolested by pirates.

midspace commented 8 years ago

It certainly can be done. That code can be implemented pretty easily. We would need to decide on how often it ran though, ie., once an hour.

jpcsupplies commented 7 years ago

Servers are getting able to handle a lot more players at once, so admins are having issues with particular items like iron ore/ingot getting quite a lot overstocked in NPC markets. Although we planned to do ambient traders for low stock (and probably high stock) in the short term implementing a sliding price scale, at least on NPC markets should be a quick an easy solution here. Other possible solutions is having markets trade automatically with each other to shuffle items around but it is probably more immersive if players do the shuttling. We also planned for transport tycoon style subsidies so it might be a good time to start implementing these as from a logic perspective, it shouldn't be too difficult.

Next questions is should the scales be hardcoded rules or flexible, or simply binary (ie admins can turn it on or off but rules are static)

Suggested logic considerations: 1: the current unit price effects the point that the sliding scales start to occur. This stops high value ores being trashed in price too quickly, and stops junk ores becoming valuable.

2: the amount of sliding should scale based on current stock levels

3: sell prices do not immediately drop, but if the buy price becomes more than half the sell price start dropping those too just not as far.

4: price check runs immediately after a sale eliminating need for timer lag; and reducing "bill shock" as only one price change occurs per sale even if the current price is unsustainable, and would likely scale further on subsequent checks. This creates stockmarket tension too.. (price is dropping sell sell sell, price is too cheap buy buy buy)

5: price changes should be represented as a percentage so that hardcoded pricing do not rig the market


eg. (probably better as a case/switch structure but using if for example purposes)
//buy price scaling (triggered at sell to server event)
if ((buyprice <= 1) && (on hand >= 500000)) { buyprice -= (buyprice * 0.50); return; } //reduce price 50% 
if ((buyprice > 1) && (buyprice <= 50) && (on hand >= 200000)) { buyprice = (buyprice * 0.75); return; } //reduce by 25%
if ((buyprice > 50) && (buyprice <= 150) && (on hand >= 150000)) { buyprice = (buyprice * 0.85); return; }  //reduce 15%
if ((buyprice > 150) && (buyprice <= 300) && (on hand >= 100000)) { buyprice = (buyprice * 0.90); return; }  //reduce 10%
if ((buyprice > 300) && (buyprice <= 1000) && (on hand >= 50000)) { buyprice = (buyprice * 0.95); return; }  //reduce 5%
if ((buyprice >1000) && (buyprice <= 5000) && (on hand >= 10000)) { buyprice = (buyprice * 0.97); return; }  //reduce 3%
if ((buyprice >5000) && (buyprice <= 15000) && (on hand >= 5000)) { buyprice = (buyprice * 0.98); return; }  //reduce 2%
if ((buyprice >15000)  && (on hand >= 500)) { buyprice = (buyprice * 0.99); return; }  //reduce 1%

//sell to player price scaling (triggered at sell to server event) in theory should never drop below buy
if (sellprice > (buyprice * 2)  {
 if ((sellprice <= 1) && (on hand >= 500000)) {sellprice = sellprice * 0.60); return; } //reduce price 40% 
 if ((sellprice > 1) && (sellprice <= 50) && (on hand >= 200000)) { sellprice = (sellprice * 0.85); return; } //reduce by 15%
 if ((sellprice > 50) && (sellprice <= 150) && (on hand >= 150000)) { sellprice = (buyprice * 0.90); return; }  //reduce 10%
 if ((sellprice > 150) && (buyprice <= 300) && (on hand >= 100000)) { sellprice = (buyprice * 0.95); return; }  //reduce 5%
 if ((sellprice > 300) && (sellprice <= 1000) && (on hand >= 50000)) { sellprice = (sellprice * 0.96); return; }  //reduce 4%
 if ((sellprice >1000) && (sellprice <= 5000) && (on hand >= 10000)) { sellprice = (sellprice * 0.97); return; }  //reduce 3%
 if ((sellprice >5000) && (sellprice <= 15000) && (on hand >= 5000)) { sellprice = (sellprice * 0.98); return; }  //reduce 2%
 if ((sellprice >15000)  && (on hand >= 500)) { sellprice = (sellprice * 0.99); return; }  //reduce 1%
}

Some sort of buy logic as well that takes price up too if stock gets short etc.. (not had time to write it yet)

jpcsupplies commented 7 years ago

Added a floor value for dropping price. Looks like it would be wise to add a price reaction to the size of a sale as well. Not just the stock on hand. To make it react more like a stock market.

jpcsupplies commented 7 years ago

note to self - we drop the buy price if there is too much stock we raise the sell price if stock becomes rare we will also need a way to raise the buy price again when stock is low we also need a way to lower the sell price if we are overstocked

jpcsupplies commented 7 years ago

@midspace So, I have been bouncing ideas off myself on my (broken) test branch. This morning it occurs to me like divine inspiration.. if I go ahead with reactive pricing as I was.. (See prior post) it would alter the NPC market price in the database. Although IMO that is not a bad idea; admins that set very specific base price might get annoyed... and players will be able to manipulate the price by dumping stock or pumping stock.. which incidentally is quite realistic, that's exactly how the crypto currency exchanges work, and WHY they work. But from our perspective it will become troublesome later on.

What I came up with instead should in theory be slightly simpler but is less manipulable - What if we hang the NPC market sliding price logic off something /like/ the LCD logic which checks price/stock prior to the player seeing it, and the adjusted price is what shows. - almost like your auto markup rules suggestion. Ie, we never actually alter the base price. Instead we have rules similar to my psuedocode above, that takes the base price THEN applies it like a filter automatically based on current stock. This reduces the number of potential price changes, eliminates the need to pay close attention to price, but we can use more dramatic ones.. (using geometric logic even 4 rules are significant, 10%(90% of price) then 50% (half off price) then 75%(25% of price) then 90%(10% of price)- or off base price 90% 45% 11% 1%)

This has some advantages over my previous approach -

  1. This allows the admin to configure the reactive price points (only 4!) % and at what qty.
  2. When we implement the transport tycoon subsidy logic - we already have the necessary logic in place, we just need to add in a check of player ID and check if they had a subsidy applied against that market.
  3. The same logic can possibly work with player markets for subsidies too, since it should be in the same buy/sell area of code.
  4. We could code in a number of price points option. Database: Qty, % impact. Default is 4 points. But its just a c# list and can be as many or as few as desired by server admin.

Main disadvantages;

  1. The overstock effect has quite a significant effect on price potentially. Maybe 3 steps is safer. Or more steps but smaller changes.
  2. We would have to be very careful with the under stock logic, or price could rise too high. May require some sort of cap logic or setting. Eg, no more than 200% increase etc configurable.
  3. Still a possibility of price manipulation just not as significant.

Our new logic would be along the lines of Assuming we have an item "fuzzy dice" assuming item(I).qty was 20,000 - So we have too many - assuming item(I).priceGivenToPlayer_sell = $100 assuming item(I).priceGivenToPlayer_buy = $50 assuming pricepoint(x).percentImpact was 0.90 (90%) assuming pricepoint(x).qty was 15,000 and the next price point was at 50,000 (so never applies)

x=0
repeat
    if ((item(I).qty > pricepoint(x).qty)  and (not pricepoint(x).percentImpact >=1)) then
    {
        item(I).priceGivenToPlayer.sell=item(I).priceGivenToPlayer_sell*pricepoint(x).percentImpact
        item(I).priceGivenToPlayer.buy=item(I).priceGivenToPlayer_buy*pricepoint(x).percentImpact
    } else { 
        if ((item(I).qty <= pricepoint(x).qty)  and (pricepoint(x).percentImpact >1)) then
        {
            item(I).priceGivenToPlayer.sell=item(I).priceGivenToPlayer_sell*pricepoint(x).percentImpact
            item(I).priceGivenToPlayer.buy=item(I).priceGivenToPlayer_buy*pricepoint(x).percentImpact
        }
    }
    x++
until  (x-1)==number of elements in price point list etc

What the player would get as price for "fuzzy dice" is
Sell price (to player) $90
Buy price (from player) $45

Price Point File sample:

Qty, % Impact
0,2.0   // out of stock! 200%
10,1.5 // Stock is low! 150%
50,1.1 //could be better 110%
1000,1.0 //Stock is just right no change
15000,0.90 //Stock is getting a bit full 90% (10% off)
50000,0.50 //Ok way too much now 50%
100000,0.25 // Getting out of hand 25%
200000,0.10 //Lets dump this stock 10%
midspace commented 7 years ago

@TheEngineer50 We don't have a copy of https://github.com/TheEngineer50/SEPowerShellTools/blob/master/marketmaint.ps1 And it appears it is no longer available.

jpcsupplies commented 7 years ago

Note to self - add char field to the price adjustment entry point, to set if it is a buy (b) or sell (s) price being altered. Add some sort of bias - ie Favor buy price reductions on high stock, over sell price drops, and favor sell price increases on low stock. Treat it like a real capitalist is setting the pricing; emphasis on profits. (edit: wow since when is C# dumb as a brick.. it cannot tell when a char is a char without overriding type when you populate it.. nor can it tell the difference between a decimal and a double.. i miss perl lol) more notes to self: convert back to an array int[] terms = termsList.ToArray();

jpcsupplies commented 7 years ago

Ok buy or sell price bias implemented crudely.

Now need to add a item price vs size of reaction filter, or track the size of transactions

At the moment if i have 500 displays at 10 each. Then buy them all reducing stuck to under 10, thus increasing buy price, I can immediately sell them all back to make a profit, and repeat until NPC is out of money. Need a way (such as a price change cool off or add further bias based on the value of the goods. Any suggestions?

jpcsupplies commented 7 years ago

@midspace are you able to add in the overlap/undercut zone logic: "lowest (in stock) tradezone sell to player price in range of player/lcd shows as current stock/sell price"
and the "highest (available funds) tradezone buy from player price shows as current buy/price"

Sundry modifiers: If the lowest sell to player price has no stock show the next one down with stock etc. If they all have no stock show the "sell to player" price from the market with the highest (available funds) buy from player price. (as this is the market the stock will go into anyway)

Effect should also apply to overlapping player zones not just players overlapping npc zones. *should we also check for overlapping npc zones - given this should never happen?

Reactive pricing should not change player price.. but may need to factor in what the npc market adjusted price is, when deciding which price dominates where an npc zone overlaps a player zone.

If the owner of an overlapping player zone tries to trade when it overlaps an npc it should prompt the player to specify the market to trade with.

low/high price should effect /pricelist too unless they specify a market name.

This sort of logic will probably replace the need for the offer/stockmarket #103 so that can be closed too


Also dumb question - did we get around to loading the price scaling rules from a file? I originally coded the logic to decode a csv formatted dataset, but I completely forget if we got around to writing that to a file to read at startup or not.. I know i worked out some test file logic and commented it out as it was writing to global not map folder.. but it has totally slipped my mind if we ended up reading that file if it exists now.

midspace commented 7 years ago

I've left appropriate locations to pick and choose a market for overlapping markets, but the problem I couldn't get my head around was inadequate stock in any or all markets, and instead having it buy part lots from each market zone to fill the entire buy order.

Yes, price scaling is in. I'm sure I documented it, but I cannot find it. The file is called "EconPriceScale.xml" And is easy to read XML.

<?xml version="1.0" encoding="utf-16"?>
<EconReactivePricing xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <EconReactivePrices>
    <PricePoint>10</PricePoint>
    <PriceChange>1.1</PriceChange>
    <Description>Critical stock 10 or less 10% increase</Description>
  </EconReactivePrices>
  <EconReactivePrices>
    <PricePoint>50</PricePoint>
    <PriceChange>1.1</PriceChange>
    <Description>Low Stock 11 to 50 10% increase</Description>
  </EconReactivePrices>
  <EconReactivePrices>
    <PricePoint>100</PricePoint>
    <PriceChange>1.05</PriceChange>
    <Description>Could be better 51 to 100 5% increase</Description>
  </EconReactivePrices>
  <EconReactivePrices>
    <PricePoint>1000</PricePoint>
    <PriceChange>1</PriceChange>
    <Description>About right 101 to 5000 no change</Description>
  </EconReactivePrices>
  <EconReactivePrices>
    <PricePoint>5000</PricePoint>
    <PriceChange>0.95</PriceChange>
    <Description>Bit high  5001- 10000 drop price 5%</Description>
  </EconReactivePrices>
  <EconReactivePrices>
    <PricePoint>10000</PricePoint>
    <PriceChange>0.95</PriceChange>
    <Description>Getting fuller 10001 to 50000 drop another 5%</Description>
  </EconReactivePrices>
  <EconReactivePrices>
    <PricePoint>50000</PricePoint>
    <PriceChange>0.90</PriceChange>
    <Description>Way too much now drop another 10%</Description>
  </EconReactivePrices>
  <EconReactivePrices>
    <PricePoint>100000</PricePoint>
    <PriceChange>0.50</PriceChange>
    <Description>Getting out of hand drop another 50%</Description>
  </EconReactivePrices>
  <EconReactivePrices>
    <PricePoint>200000</PricePoint>
    <PriceChange>0.25</PriceChange>
    <Description>Ok we need to dump this stock now 75% price drop</Description>
  </EconReactivePrices>
</EconReactivePricing>
jpcsupplies commented 5 years ago

Basically an extra admin command to allow admin to enable/disable the exploitable pricing logic yes? I am considering other ways we can do this and still minimising explotation.. but so far they all require significant more complexity to the pricing logic; and gameplay rules.

(Example when a player sells item X to station Y, they are then restricted from BUYING item X from station Y for 5 minutes or until they go to another trade zone etc)

This wouldnt harm legitimate traders, who would be mostly selling item X and using the money to buy item Z, and would inconvenience players using the stock changes to manipulate the price to clean out the NPC's money,

But it is certainly a lot more complexity since we now need timers and price tables tracking all the items and players..

SplenectomY commented 5 years ago

I went the route of breaking up large transactions into smaller amounts automatically in the code. Testing it on my DS, looks fine. If you want to see it, its [STC] Econ server. Once I get it nice looking and not spamming the chat, I'll submit it here. Not sure how active the development is on this mod.

jpcsupplies commented 5 years ago

If you submit some code we will certainly look it over, and add in stuff we like. Temar added some nice ship selling stuff that basically nailed one of the ENH's we already had in our roadmap - midspace did a quick code analysis; tidied up a few rough bits ran it on a dev version of the mod for a few days then we released it in the public version and added Temar to the credits.

We just dont necessarily see right away when a push request is sent - as we (myself/midspace) are often quite busy in real life and cant aways check our email or github but we will get to it.

The current reactive pricing core is deliberately simple to make tweaking easy, and because we hope to add in a "trade contract" mission system at some point, where the first player to transport goods to a particular station gets a bonus contract price. The current system makes it pretty easy to add a contract price bonus.

SplenectomY commented 5 years ago

I plan on it! I've got a lot of internal testing to do, since right now it's absurdly verbose, but basically I just call a do{}while{} for the buy/sell quantity, subtracting X from the qty each time and then set the reactive pricing XML to the same X interval. Stops the exploit, but repeats the transaction chat notifications on each iteration. I'll toss you something once I get it all fixed up!

And yeah I figured you're very busy. I didn't like my original PR so I removed it for further testing before I go there. I'd rather take as much load off of you guys as possible by doing a lot of testing myself and getting the code just about up to snuff before I send it over.