Increasing trades.price decimal scale (#89)

* Changing trades.price to have a larger scale - a scale of 4 causes destructive rounding when calculating transaction cost; changes to the UI to allow for inputting and showing increased scale trade prices; test case
This commit is contained in:
Michael Studman
2025-10-22 03:22:24 +11:00
committed by GitHub
parent 3aea1513d1
commit ea7ce13a7d
6 changed files with 50 additions and 5 deletions

View File

@@ -48,14 +48,14 @@
inline: true,
placeholder: "100",
value: if options[:value]
sprintf("%.#{currency.default_precision}f", options[:value])
sprintf("%.#{options[:precision].presence || currency.default_precision}f", options[:value])
elsif form.object && form.object.respond_to?(amount_method)
val = form.object.public_send(amount_method)
sprintf("%.#{currency.default_precision}f", val) if val.present?
sprintf("%.#{options[:precision].presence || currency.default_precision}f", val) if val.present?
end,
min: options[:min] || -99999999999999,
max: options[:max] || 99999999999999,
step: currency.step,
step: options[:step] || currency.step,
disabled: options[:disabled],
data: {
"money-field-target": "amount",

View File

@@ -50,7 +50,7 @@
<% if %w[buy sell].include?(type) %>
<%= form.number_field :qty, label: t(".qty"), placeholder: "10", min: 0.000000000000000001, step: "any", required: true %>
<%= form.money_field :price, label: t(".price"), required: true %>
<%= form.money_field :price, label: t(".price"), step: 'any', precision: 10, required: true %>
<% end %>
</div>

View File

@@ -40,6 +40,8 @@
disable_currency: true,
auto_submit: true,
min: 0,
step: "any",
precision: 10,
disabled: @entry.linked? %>
<% end %>
<% end %>

View File

@@ -0,0 +1,9 @@
class IncreaseTradePricePrecision < ActiveRecord::Migration[7.2]
def up
change_column :trades, :price, :decimal, precision: 19, scale: 10
end
def down
change_column :trades, :price, :decimal, precision: 19, scale: 4
end
end

2
db/schema.rb generated
View File

@@ -789,7 +789,7 @@ ActiveRecord::Schema[7.2].define(version: 2025_08_08_143007) do
create_table "trades", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t|
t.uuid "security_id", null: false
t.decimal "qty", precision: 19, scale: 4
t.decimal "price", precision: 19, scale: 4
t.decimal "price", precision: 19, scale: 10
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "currency"

View File

@@ -20,4 +20,38 @@ class TradeTest < ActiveSupport::TestCase
name = Trade.build_name("buy", 0.25, "BTC")
assert_equal "Buy 0.25 shares of BTC", name
end
test "price scale is preserved at 10 decimal places" do
security = Security.create!(ticker: "TEST", exchange_operating_mic: "XNAS")
# up to 10 decimal places — should persist exactly
precise_price = BigDecimal("12.3456789012")
trade = Trade.create!(
security: security,
price: precise_price,
qty: 10000,
currency: "USD"
)
trade.reload
assert_equal precise_price, trade.price
end
test "price is rounded to 10 decimal places" do
security = Security.create!(ticker: "TEST", exchange_operating_mic: "XNAS")
# over 10 decimal places — will be rounded
price_with_too_many_decimals = BigDecimal("1.123456789012345")
trade = Trade.create!(
security: security,
price: price_with_too_many_decimals,
qty: 1,
currency: "USD"
)
trade.reload
assert_equal BigDecimal("1.1234567890"), trade.price
end
end