mirror of
https://github.com/maybe-finance/maybe.git
synced 2025-07-19 05:09:38 +02:00
Handle bad API data for trade quantity signage (#2416)
This commit is contained in:
parent
f3ab4a27ee
commit
e60b5df442
2 changed files with 59 additions and 3 deletions
|
@ -43,14 +43,14 @@ class PlaidAccount::Investments::TransactionsProcessor
|
||||||
end
|
end
|
||||||
|
|
||||||
entry.assign_attributes(
|
entry.assign_attributes(
|
||||||
amount: transaction["quantity"] * transaction["price"],
|
amount: derived_qty(transaction) * transaction["price"],
|
||||||
currency: transaction["iso_currency_code"],
|
currency: transaction["iso_currency_code"],
|
||||||
date: transaction["date"]
|
date: transaction["date"]
|
||||||
)
|
)
|
||||||
|
|
||||||
entry.trade.assign_attributes(
|
entry.trade.assign_attributes(
|
||||||
security: resolved_security_result.security,
|
security: resolved_security_result.security,
|
||||||
qty: transaction["quantity"],
|
qty: derived_qty(transaction),
|
||||||
price: transaction["price"],
|
price: transaction["price"],
|
||||||
currency: transaction["iso_currency_code"]
|
currency: transaction["iso_currency_code"]
|
||||||
)
|
)
|
||||||
|
@ -87,4 +87,21 @@ class PlaidAccount::Investments::TransactionsProcessor
|
||||||
def transactions
|
def transactions
|
||||||
plaid_account.raw_investments_payload["transactions"] || []
|
plaid_account.raw_investments_payload["transactions"] || []
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Plaid unfortunately returns incorrect signage on some `quantity` values. They claim all "sell" transactions
|
||||||
|
# are negative signage, but we have found multiple instances of production data where this is not the case.
|
||||||
|
#
|
||||||
|
# This method attempts to use several Plaid data points to derive the true quantity with the correct signage.
|
||||||
|
def derived_qty(transaction)
|
||||||
|
reported_qty = transaction["quantity"]
|
||||||
|
abs_qty = reported_qty.abs
|
||||||
|
|
||||||
|
if transaction["type"] == "sell" || transaction["amount"] < 0
|
||||||
|
-abs_qty
|
||||||
|
elsif transaction["type"] == "buy" || transaction["amount"] > 0
|
||||||
|
abs_qty
|
||||||
|
else
|
||||||
|
reported_qty
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -6,7 +6,6 @@ class PlaidAccount::Investments::TransactionsProcessorTest < ActiveSupport::Test
|
||||||
@security_resolver = PlaidAccount::Investments::SecurityResolver.new(@plaid_account)
|
@security_resolver = PlaidAccount::Investments::SecurityResolver.new(@plaid_account)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
test "creates regular trade entries" do
|
test "creates regular trade entries" do
|
||||||
test_investments_payload = {
|
test_investments_payload = {
|
||||||
transactions: [
|
transactions: [
|
||||||
|
@ -16,6 +15,7 @@ class PlaidAccount::Investments::TransactionsProcessorTest < ActiveSupport::Test
|
||||||
"type" => "buy",
|
"type" => "buy",
|
||||||
"quantity" => 1, # Positive, so "buy 1 share"
|
"quantity" => 1, # Positive, so "buy 1 share"
|
||||||
"price" => 100,
|
"price" => 100,
|
||||||
|
"amount" => 100,
|
||||||
"iso_currency_code" => "USD",
|
"iso_currency_code" => "USD",
|
||||||
"date" => Date.current,
|
"date" => Date.current,
|
||||||
"name" => "Buy 1 share of AAPL"
|
"name" => "Buy 1 share of AAPL"
|
||||||
|
@ -108,4 +108,43 @@ class PlaidAccount::Investments::TransactionsProcessorTest < ActiveSupport::Test
|
||||||
assert_equal Date.current, entry.date
|
assert_equal Date.current, entry.date
|
||||||
assert_equal "Miscellaneous fee", entry.name
|
assert_equal "Miscellaneous fee", entry.name
|
||||||
end
|
end
|
||||||
|
|
||||||
|
test "handles bad plaid quantity signage data" do
|
||||||
|
test_investments_payload = {
|
||||||
|
transactions: [
|
||||||
|
{
|
||||||
|
"transaction_id" => "123",
|
||||||
|
"type" => "sell", # Correct type
|
||||||
|
"subtype" => "sell", # Correct subtype
|
||||||
|
"quantity" => 1, # ***Incorrect signage***, this should be negative
|
||||||
|
"price" => 100, # Correct price
|
||||||
|
"amount" => -100, # Correct amount
|
||||||
|
"iso_currency_code" => "USD",
|
||||||
|
"date" => Date.current,
|
||||||
|
"name" => "Sell 1 share of AAPL"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
@plaid_account.update!(raw_investments_payload: test_investments_payload)
|
||||||
|
|
||||||
|
@security_resolver.expects(:resolve).returns(OpenStruct.new(
|
||||||
|
security: securities(:aapl)
|
||||||
|
))
|
||||||
|
|
||||||
|
processor = PlaidAccount::Investments::TransactionsProcessor.new(@plaid_account, security_resolver: @security_resolver)
|
||||||
|
|
||||||
|
assert_difference [ "Entry.count", "Trade.count" ], 1 do
|
||||||
|
processor.process
|
||||||
|
end
|
||||||
|
|
||||||
|
entry = Entry.order(created_at: :desc).first
|
||||||
|
|
||||||
|
assert_equal -100, entry.amount
|
||||||
|
assert_equal "USD", entry.currency
|
||||||
|
assert_equal Date.current, entry.date
|
||||||
|
assert_equal "Sell 1 share of AAPL", entry.name
|
||||||
|
|
||||||
|
assert_equal -1, entry.trade.qty
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue