Using RapidGrails ReportService
package fundmanagement
import fundmanagement.reports.PortfolioPerformance
import fundmanagement.transactions.PortfolioTransaction
class PortfolioPerformanceService {
def symbolSynchronizationService
def report(params) {
def map = [:]
def id = 1
def client
if(params.client)
client = Client.findById(params.client.id)
else
client = Client.findById(params.clientId)
def portfolioTransactions = PortfolioTransaction.findAllByClient(client)
if(params.fromDate_year)
{
def fromDate = Date.parse("yyyy/MM/dd", params.fromDate_year + "/" + params.fromDate_month + "/" + params.fromDate_day)
portfolioTransactions = portfolioTransactions.findAll {item -> item.transactionDate >= fromDate}
}
if(params.toDate_year)
{
def toDate = Date.parse("yyyy/MM/dd", params.toDate_year + "/" + params.toDate_month + "/" + params.toDate_day)
portfolioTransactions = portfolioTransactions.findAll {item -> item.transactionDate <= toDate}
}
portfolioTransactions.each {
if (it.symbol.insCode != "999") {
if (map[it.symbol]) {
def perf = map[it.symbol]
perf.costPerShare = (it.transactionType in ["buy", "init"]) ? (((perf.costPerShare * perf.buyCount) + (it.unitCount * it.unitPrice))/(perf.buyCount + it.unitCount)) : perf.costPerShare
perf.sellPrice = (it.transactionType == "sell") ? (((perf.sellPrice * perf.sellCount) + (it.unitCount * it.unitPrice))/(perf.sellCount + it.unitCount)) : perf.sellPrice
perf.buyCount += (it.transactionType in ["buy", "init"]) ? it.unitCount : 0
perf.sellCount += (it.transactionType == "sell") ? it.unitCount : 0
} else {
def perf = new PortfolioPerformance()
perf.id = id++
perf.symbol = it.symbol.toString()
perf.buyCount = (it.transactionType in ["buy", "init"]) ? it.unitCount : 0
perf.sellCount = (it.transactionType == "sell") ? it.unitCount : 0
perf.costPerShare = (it.transactionType in ["buy", "init"]) ? it.unitPrice : 0
perf.sellPrice = (it.transactionType == "sell") ? it.unitPrice : 0
if (it.symbol.insCode == "999")
perf.currentSharePrice = 1
else {
perf.currentSharePrice = symbolSynchronizationService.getSymbolPrice(it.symbol)
}
map[it.symbol] = perf
}
}
}
def sumMarketValue = 0.0
def sumTotalOpenCost = 0.0
def sumTotalClosedCost = 0.0
def sumClosedPositionsProfitLoss = 0.0
def sumOpenPositionsProfitLoss = 0.0
def sumTotalProfitLoss = 0.0
map.values().each { PortfolioPerformance perf ->
perf.remained = perf.buyCount - perf.sellCount
perf.totalClosedCost = perf.sellCount * perf.costPerShare
perf.totalOpenCost = perf.remained * perf.costPerShare
perf.marketValue = perf.remained * perf.currentSharePrice
perf.closedPositionsProfitLoss = perf.sellCount * (perf.sellPrice - perf.costPerShare)
perf.openPositionsProfitLoss = perf.remained * (perf.currentSharePrice - perf.costPerShare)
perf.totalProfitLoss = perf.closedPositionsProfitLoss + perf.openPositionsProfitLoss
perf.performance = perf.totalProfitLoss / (perf.totalOpenCost + perf.totalClosedCost)
sumMarketValue += perf.marketValue
sumTotalOpenCost += perf.totalOpenCost
sumTotalClosedCost += perf.totalClosedCost
sumClosedPositionsProfitLoss += perf.closedPositionsProfitLoss
sumOpenPositionsProfitLoss += perf.openPositionsProfitLoss
sumTotalProfitLoss += perf.totalProfitLoss
}
def userdata = [:]
//userdata.marketValue = "<div>${String.format("%.2f", sumMarketValue)}</div><div>2</div>"
userdata.marketValue = "${String.format("%.2f", sumMarketValue)}"
userdata.totalOpenCost = String.format("%.2f", sumTotalOpenCost)
userdata.totalClosedCost = String.format("%.2f", sumTotalClosedCost)
userdata.closedPositionsProfitLoss = String.format("%.2f", sumClosedPositionsProfitLoss)
userdata.openPositionsProfitLoss = String.format("%.2f", sumOpenPositionsProfitLoss)
userdata.totalProfitLoss = String.format("%.2f", sumTotalProfitLoss)
userdata.symbol='جمع'
[list: map.values(), userdata: userdata]
}
}
package fundmanagement.reports
import ar.com.fdvs.dj.domain.DJCalculation
import rapidgrails.Field
class PortfolioPerformanceController {
def reportService
def portfolioPerformanceService
def messageSource
static allowedMethods = [save: "POST", update: "POST", delete: "POST"]
def index() {
redirect(action: "list", params: params)
}
def list() {}
def grid() {}
def chart() {
def locale = new Locale("en")
def list = portfolioPerformanceService.report(params).list
def series = [
[name: messageSource.getMessage("portfolioPerformance.closedPositionsProfitLoss", null, "Closed Positions Profit/Loss", locale), data: list.collect { it.closedPositionsProfitLoss }],
[name: messageSource.getMessage("portfolioPerformance.openPositionsProfitLoss", null, "Open Positions Profit/Loss", locale), data: list.collect { it.openPositionsProfitLoss }],
[name: messageSource.getMessage("portfolioPerformance.totalProfitLoss", null, "Total Profit/Loss", locale), data: list.collect { it.totalProfitLoss }]
]
def xAxis = list.collect { it.symbol }
def title = messageSource.getMessage("portfolioPerformance.profitLoss.chart", null, "Portfolio Performance", locale)
[title: title, subtitle: "", xAxis: xAxis]
}
def pdf() {
export("pdf")
}
def xls() {
export("xls")
}
private def export(format) {
def reportTitle = "Portfolio Performance"
def subTitle = "smaller title goes here!"
def fields = []
fields << Field.String(name: "symbol")
fields << Field.Integer(name: "buyCount")
fields << Field.Integer(name: "sellCount")
fields << Field.Integer(name: "remained")
fields << Field.Double(name: "costPerShare")
fields << Field.Double(name: "totalClosedCost", footerCalculation: DJCalculation.SUM)
fields << Field.Double(name: "totalOpenCost", footerCalculation: DJCalculation.SUM)
fields << Field.Double(name: "sellPrice")
fields << Field.Double(name: "currentSharePrice")
fields << Field.Double(name: "marketValue", footerCalculation: DJCalculation.SUM)
fields << Field.Double(name: "closedPositionsProfitLoss", footerCalculation: DJCalculation.SUM)
fields << Field.Double(name: "openPositionsProfitLoss", footerCalculation: DJCalculation.SUM)
fields << Field.Double(name: "totalProfitLoss", footerCalculation: DJCalculation.SUM)
fields << Field.Double(name: "performance")
def columns = fields.collect {it.title}.toArray(new String[0])
reportService.CreateReportFile(reportTitle, subTitle, fields, portfolioPerformanceService.report(params).list, columns, format, response, request, true)
}
}
package fundmanagement.reports
class PortfolioPerformance {
String symbol
Integer buyCount
Integer sellCount
Integer remained
Double costPerShare
Double totalClosedCost
Double totalOpenCost
Double sellPrice
Double currentSharePrice
Double marketValue
Double closedPositionsProfitLoss
Double openPositionsProfitLoss
Double totalProfitLoss
Double performance
static charts = {
chart(title: "profitLoss", subtitle: "", variable: "symbol") {
column("closedPositionsProfitLoss")
column("openPositionsProfitLoss")
column("totalProfitLoss")
}
chart(title: "performance", subtitle: "", variable: "symbol") {
column("performance")
}
}
static constraints = {
symbol()
buyCount()
sellCount()
remained()
costPerShare()
totalClosedCost()
totalOpenCost()
sellPrice()
currentSharePrice()
marketValue()
closedPositionsProfitLoss()
openPositionsProfitLoss()
totalProfitLoss()
performance()
}
}