Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 17 additions & 18 deletions golang/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,33 +21,32 @@ go test ./...

Repository はモック実装としてin-memoryにデータを保持していますが、RDBを使う想定で回答してください。

### 株と評価額
### 銘柄と保有額

- 株には株数(qty)があります(例: 1株、2株)
- 株には1株あたりの市場価格があります(例: 1株あたり100円)
- 例: 顧客が5株保有している場合、評価額はこの時点では `5株 × 100円 = 500円` となります
- 顧客は銘柄ごとに保有額(円)を保持します(例: A銘柄を 500 円分保有する)
- 簡略化のため、株数や市場価格は扱わず、各銘柄を金額(円)で直接保有するものとします

### ロボアドバイザーサービス

- **顧客の口座**
- 新規拠出を行うと、口座がすぐに開きます
- 新規注文を行うと、口座がすぐに開きます
- 口座の中で資産を管理することになります
- **顧客の資産**
- 顧客は現金と株を保有し、総資産の5%は常に現金で保持します
- 例: 総資産100万円のうち5万円を現金として保持し、残り95万円分をいくつかの株で保有する
- 株は価格で保持するのではなく、株数で保持します
- そのため、市場価格に応じて評価額は変わることになります
- 顧客は現金と銘柄を保有し、総資産の5%は常に現金で保持します
- 例: 総資産105万円のうち5万円を現金として保持し、残り100万円分をいくつかの銘柄で保有する
- 各銘柄毎の資産は金額(円)で保持します
- **最適ポートフォリオ**
- サービスが管理する、株の評価額ベースの構成比率
- 例: A株を30%・B株を70%で保有する場合、総資産100万円のうち 5万円の現金 + A株95万円*30%分の株数 + B株95万円*70%分の株数 になるように努める
- 購入時・売却時・リバランス時には、売買後の資産比率が __現在の最適ポートフォリオ__ に近づける形での売買を実施します
- **株の売買**
- 本アプリケーションでは、注文APIを叩くと __即時__ 株の売買が成立し資産に反映出来るものとします
- サービスが管理する、銘柄の保有額ベースの構成比率(現金は含めない)
- 例: A銘柄を30%・B銘柄を70%で保有する場合、総資産105万円のうち 5万円の現金 + A銘柄30万円分 + B銘柄70万円分 になるように努める
- 購入時・売却時・リバランス時には、注文後の資産比率が __現在の最適ポートフォリオ__ に近づける形での調整を実施します
- **資産の調整**
- 本アプリケーションでは、注文APIを叩くと __即時__ 売買が成立し資産に反映出来るものとします
- 用語
- 新規拠出注文: 初めて資金を投入すること。この注文を入れることで、資産運用が始まる。
- 追加拠出注文: 追加で資金を投入すること。この注文を入れると、運用する株が増える。
- 全売却注文: 運用中の株を全て売却すること。
- リバランス注文: 運用されている株を、サービスで保有する最適ポートフォリオに近づける株の売買をすること。
- 新規注文: 初めて資金を投入すること。この注文を入れることで、資産運用が始まる。
- 追加注文: 追加で資金を投入すること。この注文を入れると、運用する金額が増える。
- 全売却注文: 運用中の銘柄を全て売却すること。
- リバランス注文: 運用されている資産を、サービスで保有する最適ポートフォリオに近づけるよう調整すること。最適ポートフォリオの比率が変更された場合に、その比率へ寄せる。
- 例: 最適ポートフォリオを `A銘柄30%+B銘柄70%` から `A銘柄50%+B銘柄50%` に変えてからリバランス注文をすると、顧客の口座も最新の最適ポートフォリオ通りの内容になる

## 確認観点

Expand Down
13 changes: 0 additions & 13 deletions golang/internal/application/repository/market_price_repository.go

This file was deleted.

29 changes: 0 additions & 29 deletions golang/internal/application/service/asset_service.go

This file was deleted.

138 changes: 0 additions & 138 deletions golang/internal/application/service/portfolio_service.go

This file was deleted.

23 changes: 6 additions & 17 deletions golang/internal/application/usecase/asset/get_asset_usecase.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import (
"errors"

"folio/codinginterview/internal/application/repository"
"folio/codinginterview/internal/application/service"
"folio/codinginterview/internal/domain"

"github.com/shopspring/decimal"
Expand All @@ -13,8 +12,8 @@ import (
var ErrUserNotFound = errors.New("user not found")

type GetAssetStockOutput struct {
Symbol domain.StockSymbol
EvaluationAmount decimal.Decimal
Symbol domain.StockSymbol
AmountJpy decimal.Decimal
}

type GetAssetUsecaseInput struct {
Expand All @@ -27,12 +26,11 @@ type GetAssetUsecaseOutput struct {
}

type GetAssetUsecase struct {
accountRepo repository.AccountRepository
marketPriceRepo repository.MarketPriceRepository
accountRepo repository.AccountRepository
}

func NewGetAssetUsecase(accountRepo repository.AccountRepository, marketPriceRepo repository.MarketPriceRepository) *GetAssetUsecase {
return &GetAssetUsecase{accountRepo: accountRepo, marketPriceRepo: marketPriceRepo}
func NewGetAssetUsecase(accountRepo repository.AccountRepository) *GetAssetUsecase {
return &GetAssetUsecase{accountRepo: accountRepo}
}

func (u *GetAssetUsecase) Run(input GetAssetUsecaseInput) (GetAssetUsecaseOutput, error) {
Expand All @@ -44,18 +42,9 @@ func (u *GetAssetUsecase) Run(input GetAssetUsecaseInput) (GetAssetUsecaseOutput
return GetAssetUsecaseOutput{}, ErrUserNotFound
}

prices, err := u.marketPriceRepo.All()
if err != nil {
return GetAssetUsecaseOutput{}, err
}

stocks := make([]GetAssetStockOutput, 0, len(account.Stocks))
for _, s := range account.Stocks {
evalAmount, err := service.EvaluateStock(s, prices)
if err != nil {
return GetAssetUsecaseOutput{}, err
}
stocks = append(stocks, GetAssetStockOutput{Symbol: s.Symbol, EvaluationAmount: evalAmount})
stocks = append(stocks, GetAssetStockOutput{Symbol: s.Symbol, AmountJpy: s.AmountJpy})
}

return GetAssetUsecaseOutput{CashAmount: account.Cash, Stocks: stocks}, nil
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import (
"errors"

"folio/codinginterview/internal/application/repository"
"folio/codinginterview/internal/application/service"
"folio/codinginterview/internal/domain"

"github.com/shopspring/decimal"
Expand All @@ -21,20 +20,17 @@ type AdditionalBuyOrderUsecaseInput struct {
}

type AdditionalBuyOrderUsecase struct {
accountRepo repository.AccountRepository
portfolioRepo repository.PortfolioRepository
marketPriceRepo repository.MarketPriceRepository
accountRepo repository.AccountRepository
portfolioRepo repository.PortfolioRepository
}

func NewAdditionalBuyOrderUsecase(
accountRepo repository.AccountRepository,
portfolioRepo repository.PortfolioRepository,
marketPriceRepo repository.MarketPriceRepository,
) *AdditionalBuyOrderUsecase {
return &AdditionalBuyOrderUsecase{
accountRepo: accountRepo,
portfolioRepo: portfolioRepo,
marketPriceRepo: marketPriceRepo,
accountRepo: accountRepo,
portfolioRepo: portfolioRepo,
}
}

Expand All @@ -56,15 +52,7 @@ func (u *AdditionalBuyOrderUsecase) Run(input AdditionalBuyOrderUsecaseInput) er
return err
}

prices, err := u.marketPriceRepo.All()
if err != nil {
return err
}

updated, err := service.AllocateAdditional(*account, input.Amount, portfolio, prices)
if err != nil {
return err
}
updated := account.AddFunds(input.Amount, portfolio)

return u.accountRepo.Upsert(input.UserId, updated)
}
Loading
Loading