Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Valuation of items #14

Open
rafabap opened this issue Apr 3, 2017 · 8 comments
Open

Valuation of items #14

rafabap opened this issue Apr 3, 2017 · 8 comments

Comments

@rafabap
Copy link

rafabap commented Apr 3, 2017

@DavoudTaghawiNejad So far we are thinking that valuation of an item should be a member function of every Item. It should take as argument the agent that is performing the valuation. This means that the Item should include all the relevant information necessary to perform its valuation inside the item instance (for example, if an item needs to look at the current market prices, the item needs a reference to the relevant market so that it can obtain the information).

In some cases there will be several different valuation functions possible. We are leaning towards putting all of those inside the Item and not inside the Agent that performs them. Because the valuation function takes as argument the identity of the agent that is performing the valuation, the function itself can deal with the different cases and decide which valuation function to use.

@davidrpugh
Copy link
Member

@rafabap I don't think that you want the item to carry around all the necessary to value it. In particular for market prices, I think it would be much better to use some kind of publish/subscribe pattern where the market publishes prices (not unlike a stock ticker) and agents subscribe to market price tickers in those markets in which they trade.

I also don't like the idea that the valuation function should take the the agent as an argument. What type signature did you have in mind for a valuation function? Here is one possibility (apologies for the Scala but there is surely a Java 8 equivalent)...

trait Value extends AnyVal

trait ValuationFunction[-T <: Tradable, +V <: Value] extends (T => V) {
 
  def apply(tradable: T): V

}

case class Price(value: Long) extends Value

case class MarketValuationFunction[-T <: Tradable](market: Price) extends ValuationFunction[T, Price] {
  def apply(tradable: T): Price = market
}

...idea would be that an when an agent needs to value a particular tradable item, it would lookup the market price for the item and then use it to create an instance of the MarketValuationFunction class which it then passes off to the data structure that will apply the function to a particular item instance to produce the value.

@bherd-rb what are your thoughts?

@bherd-rb
Copy link

bherd-rb commented Apr 4, 2017

@rafabap @davidrpugh I agree with David. The valuation function should, in my opinion, definitely be separated from the item itself. Reasons for that are flexibility and modularity. If the valuation function is part of the item, then people would probably soon start to subclass the item class in order to put in their own valuation functions. This might produce all sorts of problems. For example, we would have to make sure that dynamic polymorphism is ensured and working properly everywhere in order for those subclasses to integrate well with the rest of the code. Furthermore, extensive subclassing may produce concurrency issues if people start to make those subclasses stateful. I'm not familiar with how items are currently implemented, but I could imagine some of those issues emerging over time.

Following a more functional approach and passing the valuation function into the item as described by David would provide a great level of flexibility and (presumably) avoid some of the problems mentioned above.

@davidrpugh
Copy link
Member

@rafabap I think the key to solving this puzzle is to use closures to inject immutable data into the returned value function so that the value function contains all of the necessary non-item data (i.e., market prices, agent parameters, any other non-item related data) required to value an item. The item could then have a method that takes a valuation function and returns a value or the container object used to store items could have a method that takes a valuation function and then each item.

@davidrpugh
Copy link
Member

More thoughts. Valuing an Item, whether it is a Good or a Contract depends on information that is item-specific, information that is agent-specific, and public information.

Examples of Item instances with item-specific information...

sealed trait Item

trait Good extends Item

trait Contract extends Item

// item specific information is variety, quantity
case class Apple(variety: String, quantity: Long) extends Good

// item specific information is value
case class Currency(value: Long) extends Contract

Agent-specific information would be something like a utility function and its associated parameters, etc. Public information would be something like market prices, etc.

I think it is important to keep the type signature of the valuation function very simple: a generic valuation function takes an instance of a particular type of Item and maps it to a type representing some kind of Value

trait ValuationFunction[-I <: Item, +V <: AnyVal] extends (I => V)

The approach that I am advocating is that we use closures to inject both agent-specific information and public information (that an agent has access to via various information feeds that it subscribes to) into an instance of a valuation function. This function can then be passed around as need and contains all relevant information needed to value an item.

@phelps-sg
Copy link

phelps-sg commented Apr 4, 2017 via email

@davidrpugh
Copy link
Member

@phelps-sg Thanks for the suggestions. I agree that this design decision deserves careful consideration. Certainly a closure is not the only way to inject the required data in to the function. I am not necessarily averse to using a more heavy weight DI framework to achieve the same effect, but I do not feel that I know enough about the relevant trade-offs between the at least 6 different DI frameworks and approaches to confidently advocate for a particular DI solution at present.

However, isn't this decision (to replace DI with functional-programming)
orthogonal from the design of a single API call?

My advocating closures as a solution to this particular problem should not be interpreted as trying to replace DI with functional programming techniques for the entire library.

Alternatively, if it is automatically subscribing to the required
data feeds, again why do we need to inject this information via a closure?

The agent would subscribe to the data feeds, but the items that need valuing might live in an object on some other machine in a cluster. If I inject the data into the valuation function using a closure, then I can potentially pass this function as a message to that object on another machine.

@phelps-sg
Copy link

phelps-sg commented Apr 25, 2017 via email

@davidrpugh
Copy link
Member

@phelps-sg Next month @bherd-rb and I are going to start experimenting with Akka for this use case. In particular we will be using akka-actors, akka-remoting, and akka-stream.

The Akka module that focuses most specifically on your use case is akka-cluster-sharding. Quoting from the documentation:

In this context sharding means that actors with an identifier, so called entities, can be automatically distributed across multiple nodes in the cluster. Each entity actor runs only at one place, and messages can be sent to the entity without requiring the sender to know the location of the destination actor. This is achieved by sending the messages via a ShardRegion actor provided by this extension, which knows how to route the message with the entity id to the final destination.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants