Skip to content

Commit

Permalink
Added tests (belatedly), web3. Model portfolios - they have "nil" use…
Browse files Browse the repository at this point in the history
…rs. Beginnings of "copy" functionality. Added BalancerPool model. Added PriceHistory model and seeded with actual price history.
  • Loading branch information
EndymionJkb committed May 3, 2020
1 parent 94fe89d commit abe6db6
Show file tree
Hide file tree
Showing 33 changed files with 751 additions and 14 deletions.
3 changes: 3 additions & 0 deletions .rspec
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
--colour
--format doc
--require spec_helper
10 changes: 10 additions & 0 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,16 @@ gem 'jquery-ui-rails', '6.0.1'
gem 'bootstrap', '4.4.1'
gem 'haml', '5.1.2'
gem 'will_paginate', '3.3.0'
gem 'web3-eth', '0.2.38'

gem 'bootsnap', '>= 1.1.0', require: false

group :development, :test do
# Call 'byebug' anywhere in the code to stop execution and get a debugger console
gem 'byebug', platforms: [:mri, :mingw, :x64_mingw]
gem 'rspec-rails', '4.0.0'
gem 'factory_bot_rails', '5.1.1'
gem 'faker', '2.11.0'
end

group :development do
Expand All @@ -42,3 +46,9 @@ group :development do
gem 'better_errors', '2.6.0'
gem 'binding_of_caller', '0.8.0'
end

group :test do
gem 'database_cleaner-active_record', '1.8.0'
gem 'shoulda-matchers', '4.3.0'
gem 'rspec-its', '1.3.0'
end
46 changes: 46 additions & 0 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -67,16 +67,29 @@ GEM
coderay (1.1.2)
concurrent-ruby (1.1.6)
crass (1.0.6)
database_cleaner (1.8.4)
database_cleaner-active_record (1.8.0)
activerecord
database_cleaner (~> 1.8.0)
debug_inspector (0.0.3)
devise (4.7.1)
bcrypt (~> 3.0)
orm_adapter (~> 0.1)
railties (>= 4.1.0)
responders
warden (~> 1.2.3)
diff-lcs (1.3)
digest-sha3 (1.1.0)
erubi (1.9.0)
erubis (2.7.0)
execjs (2.7.0)
factory_bot (5.1.2)
activesupport (>= 4.2.0)
factory_bot_rails (5.1.1)
factory_bot (~> 5.1.0)
railties (>= 4.2.0)
faker (2.11.0)
i18n (>= 1.6, < 2)
ffi (1.12.2)
globalid (0.4.2)
activesupport (>= 4.2.0)
Expand Down Expand Up @@ -161,6 +174,27 @@ GEM
responders (3.0.0)
actionpack (>= 5.0)
railties (>= 5.0)
rlp (0.7.3)
rspec-core (3.9.1)
rspec-support (~> 3.9.1)
rspec-expectations (3.9.1)
diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.9.0)
rspec-its (1.3.0)
rspec-core (>= 3.0.0)
rspec-expectations (>= 3.0.0)
rspec-mocks (3.9.1)
diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.9.0)
rspec-rails (4.0.0)
actionpack (>= 4.2)
activesupport (>= 4.2)
railties (>= 4.2)
rspec-core (~> 3.9)
rspec-expectations (~> 3.9)
rspec-mocks (~> 3.9)
rspec-support (~> 3.9)
rspec-support (3.9.2)
ruby_dep (1.5.0)
ruby_parser (3.14.2)
sexp_processor (~> 4.9)
Expand All @@ -173,6 +207,8 @@ GEM
sprockets-rails
tilt
sexp_processor (4.14.1)
shoulda-matchers (4.3.0)
activesupport (>= 4.2.0)
spring (2.1.0)
spring-watcher-listen (2.0.1)
listen (>= 2.7, < 4.0)
Expand All @@ -199,6 +235,9 @@ GEM
activemodel (>= 5.0)
bindex (>= 0.4.0)
railties (>= 5.0)
web3-eth (0.2.38)
digest-sha3 (~> 1.1.0)
rlp (~> 0.7.3)
websocket-driver (0.7.1)
websocket-extensions (>= 0.1.0)
websocket-extensions (0.1.4)
Expand All @@ -215,7 +254,10 @@ DEPENDENCIES
bootsnap (>= 1.1.0)
bootstrap (= 4.4.1)
byebug
database_cleaner-active_record (= 1.8.0)
devise (= 4.7.1)
factory_bot_rails (= 5.1.1)
faker (= 2.11.0)
haml (= 5.1.2)
haml-rails (= 2.0.1)
jquery-rails (= 4.3.5)
Expand All @@ -225,11 +267,15 @@ DEPENDENCIES
puma (= 3.12.4)
rails (= 5.2.4.2)
rb-readline (= 0.5.5)
rspec-its (= 1.3.0)
rspec-rails (= 4.0.0)
sassc-rails (= 2.1.2)
shoulda-matchers (= 4.3.0)
spring
spring-watcher-listen (~> 2.0.0)
uglifier (= 4.2.0)
web-console (>= 3.3.0)
web3-eth (= 0.2.38)
will_paginate (= 3.3.0)

RUBY VERSION
Expand Down
16 changes: 16 additions & 0 deletions app/assets/javascripts/models.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
function render_model_graphs() {
$('.graph_data').each(function(i, obj) {
var row_id = obj.id + "_val";
var label_id = obj.id + "_label";
var data = {'data': $('#' + row_id).val(), 'label': $('#' + label_id).val()};

jQuery.ajax({url:'/graphs.js',
data: data,
type: "POST",
success: function(data) {
Highcharts.chart(obj.id, JSON.parse(data));
},
error: function() { alert('Oh noes!'); },
async: false});
});
}
1 change: 1 addition & 0 deletions app/assets/javascripts/web3.min.js

Large diffs are not rendered by default.

31 changes: 31 additions & 0 deletions app/controllers/graphs_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
class GraphsController < ApplicationController
respond_to :js

def create
data = Hash.new
data[:chart] = {:type => 'pie'}
data[:title] = {:text => params[:label]}
data[:subtitle] = {:text => ''}
data[:plotOptions] = {:series => {:dataLabels => {:enabled => true, :distance => -30, :format => '{point.name}<br>{point.y:.1f}%'}}}

sections = []

slices = params[:data].split('/')
slices.each do |div|
fields = div.split(':')
yval = fields[1].to_f
if yval > 0
sections.push({:name => fields[0], :y => yval, :drilldown => nil})
end
end

data[:series] = [{:name => '',
:colorByPoint => true,
:data => sections}]

respond_to do |format|
format.js { render :json => data.to_json.html_safe }
format.html { redirect_to root_path }
end
end
end
12 changes: 12 additions & 0 deletions app/controllers/pies_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,18 @@ def update_allocation
end
end

# Model portfolios
def index
@models = Pie.where(:user_id => nil)
end

def copy
@pie = Pie.find(params[:id])
@to_copy = Pie.find(params[:src])

redirect_to edit_py_path(@pie), :notice => "Copied #{@to_copy.name}"
end

private
def pie_params
params.require(:pie).permit(:pct_gold, :pct_cash, :pct_crypto, :pct_equities, :name,
Expand Down
3 changes: 3 additions & 0 deletions app/controllers/static_pages_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,7 @@ class StaticPagesController < ApplicationController

def home
end

def test
end
end
18 changes: 18 additions & 0 deletions app/models/balancer_pool.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# == Schema Information
#
# Table name: balancer_pools
#
# id :bigint not null, primary key
# pie_id :bigint
# uma_address :string(42)
# bp_address :string(42)
# uma_expiry :date
# allocation :text
# created_at :datetime not null
# updated_at :datetime not null
#
class BalancerPool < ApplicationRecord
belongs_to :pie

validates_length_of :uma_address, :bp_address, :is => 42, :allow_nil => true
end
21 changes: 18 additions & 3 deletions app/models/pie.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
# updated_at :datetime not null
#
class Pie < ApplicationRecord
belongs_to :user
belongs_to :user, :optional => true

DEFAULT_PCT_GOLD = 25
DEFAULT_PCT_CRYPTO = 25
Expand All @@ -24,6 +24,7 @@ class Pie < ApplicationRecord

has_one :crypto
has_one :stable_coin
has_one :balancer_pool

has_and_belongs_to_many :stocks
has_and_belongs_to_many :etfs
Expand All @@ -39,8 +40,7 @@ def build_chart
data[:chart] = {:type => 'pie'}
data[:title] = {:text => 'My Personal Pie'}
data[:subtitle] = {:text => 'Click slices to view detailed holdings'}
data[:accessibility] = {:announceNewData => {:enabled => true}, :point => {:valueSuffix => '%'}}
data[:plotOptions] = {:series => {:dataLabels => {:enabled => true, :format => '{point.name}: {point.y:.1f}%'}}}
data[:plotOptions] = {:series => {:dataLabels => {:enabled => true, :format => '{point.name}<br>{point.y:.1f}%'}}}
data[:tooltip] = {:headerFormat => '<span style="font-size:11px">{series.name}</span><br>',
:pointFormat => '<span style="color:{point.color}">{point.name}</span>: <b>{point.y:.2f}%</b> of total<br/>'}
data[:series] = [build_primary_series]
Expand All @@ -49,6 +49,21 @@ def build_chart
data.to_json.html_safe
end

# Should only get called when there are etfs or stocks
def equity_graph_data
data = Hash.new
equal_weight = 100 / (etfs.count + stocks.count) rescue nil

if equal_weight
etfs.each do |e|
data[e.ticker] = equal_weight
end
data['stocks'] = equal_weight * stocks.count
end

data
end

private
def build_primary_series
# Primary series is Gold, Crypto, Cash, Equities
Expand Down
16 changes: 16 additions & 0 deletions app/models/price_history.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# == Schema Information
#
# Table name: price_histories
#
# id :bigint not null, primary key
# coin :string(8) not null
# date :date not null
# price :decimal(8, 2)
# created_at :datetime not null
# updated_at :datetime not null
#
class PriceHistory < ApplicationRecord
validates_presence_of :coin, :date, :price
validates_length_of :coin, :maximum => 8
validates_numericality_of :price, :greater_than => 0
end
4 changes: 2 additions & 2 deletions app/views/layouts/_pie_header.html.haml
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@
%ul.nav-menu.afclr
- if signed_in?
%li= link_to t('pies'), py_path(1)
%li= link_to t('stocks'), root_path #TODO contact_path
%li= link_to t('etfs'), root_path #TODO contact_path
%li= link_to t('models'), pies_path
%li= link_to t('backtest'), root_path #TODO contact_path
%li= link_to t('settings'), setting_path(1)
- else
%li= link_to t('home'), root_path
Expand Down
6 changes: 6 additions & 0 deletions app/views/pies/_table_graph.html.haml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
%div.graph_data{:id => model, :style => 'width:200px; height:200px;'}
- res = []
- data.keys.each do |key|
- res.push("#{key}:#{data[key]}")
= hidden_field_tag :graph, res.join("/"), :id => "#{model}_val"
= hidden_field_tag :label, label, :id => "#{model}_label"
2 changes: 1 addition & 1 deletion app/views/pies/edit.html.haml
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@
%input#cash_props{:type => 'text', :readonly => 'true', :style => 'width:450px;'}
#cash_slider{:style => "margin-top:-20px; width:50%;"}
%p{:style => 'margin-top:-30px'}
= link_to 'Edit Equity Allocation', edit_allocation_py_path(@pie)
%br= link_to t('edit_allocation'), edit_allocation_py_path(@pie), :class => 'btn btn-primary'

:javascript
$(document).ready(function(e) {
Expand Down
53 changes: 53 additions & 0 deletions app/views/pies/index.html.haml
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
- provide(:title, t('models'))
= render 'layouts/pie_header'
= javascript_include_tag "https://code.highcharts.com/highcharts.js"
= javascript_include_tag "https://code.highcharts.com/modules/data.js"
.c_customer.afclr
.wrapper
.re_main.afclr
.ab_head.afclr
%h1= t('models')
.in_iner_pag.afclr
%table.table.table-striped
%tr
%th Name
%th % Gold
%th % Crypto
%th % Cash
%th % Equities
%th 3m Return
%th 6m Return
%th
- @models.each do |model|
%tr
%td= model.name
%td= model.pct_gold
%td= model.pct_crypto
%td= model.pct_cash
%td= model.pct_equities
%td
%td
%td
= link_to t('copy'), copy_py_path(:id => 1, :src => model.id), :class => 'btn btn-secondary', :method => :put
%tr
%td
%td
- if model.pct_gold > 0
= render :partial => 'table_graph', :locals => {:model => "#{model.id}_gold", :label => 'Gold', :data => {'PAXG' => 100}}
%td
- if model.pct_crypto > 0
= render :partial => 'table_graph', :locals => {:model => "#{model.id}_crypto", :label => 'Crypto', :data => {model.crypto.currency_name(0) => model.crypto.pct_curr1, model.crypto.currency_name(1) => model.crypto.pct_curr2, model.crypto.currency_name(2) => model.crypto.pct_curr3}}
%td
- if model.pct_cash > 0
= render :partial => 'table_graph', :locals => {:model => "#{model.id}_cash", :label => 'Cash', :data => {model.stable_coin.currency_name(0) => model.stable_coin.pct_curr1, model.stable_coin.currency_name(1) => model.stable_coin.pct_curr2, model.stable_coin.currency_name(2) => model.stable_coin.pct_curr3}}
%td
- if model.pct_equities > 0
= render :partial => 'table_graph', :locals => {:model => "#{model.id}_equity", :label => 'Equity', :data => model.equity_graph_data}
%td
%td
%td
:javascript
$(document).ready(function(e) {
render_model_graphs();
});

6 changes: 2 additions & 4 deletions app/views/pies/show.html.haml
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,6 @@
= javascript_include_tag "https://code.highcharts.com/highcharts.js"
= javascript_include_tag "https://code.highcharts.com/modules/data.js"
= javascript_include_tag "https://code.highcharts.com/modules/drilldown.js"
= javascript_include_tag "https://code.highcharts.com/modules/exporting.js"
= javascript_include_tag "https://code.highcharts.com/modules/export-data.js"
= javascript_include_tag "https://code.highcharts.com/modules/accessibility.js"

.c_customer.afclr
.wrapper
Expand All @@ -17,7 +14,8 @@
#my_pie
%p.highcharts-description
Pie chart where the individual slices can be clicked to expose more detailed data
%p= link_to 'Edit my Allocation', edit_py_path(1)
%br
%center= link_to t('edit_allocation'), edit_py_path(1), :class => 'btn btn-primary'
:javascript
$(document).ready(function(e) {
Highcharts.chart('my_pie', #{@chart_data})
Expand Down
Loading

0 comments on commit abe6db6

Please sign in to comment.