The most notable issue that I'm having trouble with is the bit that determines quantities to buy and sell. Right now, I'm forcing them to buy/sell at least 1 or 2 items every time they bid, but the paper uses some unspecified calculation to determine what quantity the agent will desire (which can sometimes be 0 if the market isn't doing well).
The algorithm more or less 'inspires' each individual to stock up when a particular product is inexpensive. IE- the farmer may buy an extra plow if the price is really low with the expectation that a future plow will break. The product's durability in conjunction with price determines the propensity to consume. That is, the more plows the farmer has the less he will be willing to pay for a new plow. How many plows the blacksmith sells governs how many he'll produce.
How much the farmer paid for his last plow in relationship to how many plows the farmer already owns determines how many he is going to bid for. If the farmer has 0 plows, he'll always buy 1 plow unless the price-productivity trade-off doesn't add up. If the farmer has 0 plows and the price is amazing, he might buy 3 or 4 plows. If the farmer has 3 or 4 plows and the price is amazing, he'll be unlikely to buy more than one more plow. If you store the max value paid and the min value paid for plows in the farmer, and evaluate the current price with the number of plows owned, you should be able to create reasonable demand. This is more or less the basics of supply and demand.
I'm also having trouble with buyers' evaluation of when price is unacceptable - they need to be able to refuse to buy an item if the seller is charging too much, but they need to realize when the seller can't go any lower.
See above, but it's also okay to end the market if everyone has what they need.
The biggest issue though, is that I'll eventually need this to be able to adapt to items made out of different materials and craft quality - for instance, when do we buy iron tools vs copper tools? And how to set up this distinction coding-wise - I think this means each commodity will have to be a class rather than a string, with a material component, a quality component, and an item component. I'm worried this will be taxing computationally.
The invisible hand of your market will take care of that for you. Basically- Farmer needs a plow. An iron mine collapsed three seasons ago or a war began. The Farmer may prefer an iron plow, but the price of the iron plow is going to be an extension of the availability of iron over copper and the overall demand of iron, which is spiked by military demand (or even mandate- either way, military is willing to pay more even if it means inadvertantly crashing other blacksmith dependent industry) or some accident. In other words, you don't really need to worry about this- the algorithm will take care of it for you.
That aside- Copper is heavier, stronger, and maintains an edge better, but is harder to sharpen and must be cast again to repair. You only need to represent this by how many +Food a Copper Plow provides over an Iron Plow and that repairing a Copper Plow is more expensive. If Farmers have skills- like Plow Sharpening and Repairing, a Farmer with lower repair and sharpening skills will go with the Copper, while a farmer with some metal skills may want iron. An extremely good farmer would, obviously, want Copper. If you introduce product grades then availability of raw resources will govern productivity, price and demand.
Which brings me to my next question - what is the most efficient way to actually express these commodities? In my current code, is it most efficient to have them as strings, and append a string to the agent's inventory list every time they acquire one? Or just have it as a string:quantity dict, which gets its value modified each time a transaction occurs?
String manipulation is probably more taxing than using objects. You don't really need either though- just enumerate every tradeable commodity. Each plow, for example, doesn't need to be represented by a plow object. We just need a static way to access the necessary ancillary data- Who uses it, who makes it, what it is made of, and what its effect is. Like Plato's Theory of Forms. We only need to know that plows exist and how many each person has, not the state of each plow. If each enumeration is mapped to a representative static object, then we only need to know the number of plows a farmer has, not a representation of each plow.