diff --git a/app/Generator/Report/Budget/MonthReportGenerator.php b/app/Generator/Report/Budget/MonthReportGenerator.php
index 87557c8682..0934ef20c6 100644
--- a/app/Generator/Report/Budget/MonthReportGenerator.php
+++ b/app/Generator/Report/Budget/MonthReportGenerator.php
@@ -141,52 +141,10 @@ class MonthReportGenerator extends Support implements ReportGeneratorInterface
         return $this;
     }
 
-    /**
-     * @param Collection $collection
-     * @param int        $sortFlag
-     *
-     * @return array
-     */
-    private function getAverages(Collection $collection, int $sortFlag): array
-    {
-        $result = [];
-        /** @var Transaction $transaction */
-        foreach ($collection as $transaction) {
-            // opposing name and ID:
-            $opposingId = $transaction->opposing_account_id;
-
-            // is not set?
-            if (!isset($result[$opposingId])) {
-                $name                = $transaction->opposing_account_name;
-                $result[$opposingId] = [
-                    'name'    => $name,
-                    'count'   => 1,
-                    'id'      => $opposingId,
-                    'average' => $transaction->transaction_amount,
-                    'sum'     => $transaction->transaction_amount,
-                ];
-                continue;
-            }
-            $result[$opposingId]['count']++;
-            $result[$opposingId]['sum']     = bcadd($result[$opposingId]['sum'], $transaction->transaction_amount);
-            $result[$opposingId]['average'] = bcdiv($result[$opposingId]['sum'], strval($result[$opposingId]['count']));
-        }
-
-        // sort result by average:
-        $average = [];
-        foreach ($result as $key => $row) {
-            $average[$key] = floatval($row['average']);
-        }
-
-        array_multisort($average, $sortFlag, $result);
-
-        return $result;
-    }
-
     /**
      * @return Collection
      */
-    private function getExpenses(): Collection
+    protected function getExpenses(): Collection
     {
         if ($this->expenses->count() > 0) {
             Log::debug('Return previous set of expenses.');
@@ -208,34 +166,6 @@ class MonthReportGenerator extends Support implements ReportGeneratorInterface
         return $transactions;
     }
 
-    /**
-     * @return Collection
-     */
-    private function getTopExpenses(): Collection
-    {
-        $transactions = $this->getExpenses()->sortBy('transaction_amount');
-
-        return $transactions;
-    }
-
-    /**
-     * @param Collection $collection
-     *
-     * @return array
-     */
-    private function summarizeByAccount(Collection $collection): array
-    {
-        $result = [];
-        /** @var Transaction $transaction */
-        foreach ($collection as $transaction) {
-            $accountId          = $transaction->account_id;
-            $result[$accountId] = $result[$accountId] ?? '0';
-            $result[$accountId] = bcadd($transaction->transaction_amount, $result[$accountId]);
-        }
-
-        return $result;
-    }
-
     /**
      * @param Collection $collection
      *
diff --git a/app/Generator/Report/Category/MonthReportGenerator.php b/app/Generator/Report/Category/MonthReportGenerator.php
index 0a3c60be3a..654f67befc 100644
--- a/app/Generator/Report/Category/MonthReportGenerator.php
+++ b/app/Generator/Report/Category/MonthReportGenerator.php
@@ -151,52 +151,10 @@ class MonthReportGenerator extends Support implements ReportGeneratorInterface
         return $this;
     }
 
-    /**
-     * @param Collection $collection
-     * @param int        $sortFlag
-     *
-     * @return array
-     */
-    private function getAverages(Collection $collection, int $sortFlag): array
-    {
-        $result = [];
-        /** @var Transaction $transaction */
-        foreach ($collection as $transaction) {
-            // opposing name and ID:
-            $opposingId = $transaction->opposing_account_id;
-
-            // is not set?
-            if (!isset($result[$opposingId])) {
-                $name                = $transaction->opposing_account_name;
-                $result[$opposingId] = [
-                    'name'    => $name,
-                    'count'   => 1,
-                    'id'      => $opposingId,
-                    'average' => $transaction->transaction_amount,
-                    'sum'     => $transaction->transaction_amount,
-                ];
-                continue;
-            }
-            $result[$opposingId]['count']++;
-            $result[$opposingId]['sum']     = bcadd($result[$opposingId]['sum'], $transaction->transaction_amount);
-            $result[$opposingId]['average'] = bcdiv($result[$opposingId]['sum'], strval($result[$opposingId]['count']));
-        }
-
-        // sort result by average:
-        $average = [];
-        foreach ($result as $key => $row) {
-            $average[$key] = floatval($row['average']);
-        }
-
-        array_multisort($average, $sortFlag, $result);
-
-        return $result;
-    }
-
     /**
      * @return Collection
      */
-    private function getExpenses(): Collection
+    protected function getExpenses(): Collection
     {
         if ($this->expenses->count() > 0) {
             Log::debug('Return previous set of expenses.');
@@ -221,7 +179,7 @@ class MonthReportGenerator extends Support implements ReportGeneratorInterface
     /**
      * @return Collection
      */
-    private function getIncome(): Collection
+    protected function getIncome(): Collection
     {
         if ($this->income->count() > 0) {
             return $this->income;
@@ -240,85 +198,6 @@ class MonthReportGenerator extends Support implements ReportGeneratorInterface
         return $transactions;
     }
 
-    /**
-     * @SuppressWarnings(PHPMD.CyclomaticComplexity) // it's exactly five.
-     * @param array $spent
-     * @param array $earned
-     *
-     * @return array
-     */
-    private function getObjectSummary(array $spent, array $earned): array
-    {
-        $return = [];
-
-        /**
-         * @var int    $accountId
-         * @var string $entry
-         */
-        foreach ($spent as $objectId => $entry) {
-            if (!isset($return[$objectId])) {
-                $return[$objectId] = ['spent' => 0, 'earned' => 0];
-            }
-
-            $return[$objectId]['spent'] = $entry;
-        }
-        unset($entry);
-
-        /**
-         * @var int    $accountId
-         * @var string $entry
-         */
-        foreach ($earned as $objectId => $entry) {
-            if (!isset($return[$objectId])) {
-                $return[$objectId] = ['spent' => 0, 'earned' => 0];
-            }
-
-            $return[$objectId]['earned'] = $entry;
-        }
-
-
-        return $return;
-    }
-
-
-    /**
-     * @return Collection
-     */
-    private function getTopExpenses(): Collection
-    {
-        $transactions = $this->getExpenses()->sortBy('transaction_amount');
-
-        return $transactions;
-    }
-
-    /**
-     * @return Collection
-     */
-    private function getTopIncome(): Collection
-    {
-        $transactions = $this->getIncome()->sortByDesc('transaction_amount');
-
-        return $transactions;
-    }
-
-    /**
-     * @param Collection $collection
-     *
-     * @return array
-     */
-    private function summarizeByAccount(Collection $collection): array
-    {
-        $result = [];
-        /** @var Transaction $transaction */
-        foreach ($collection as $transaction) {
-            $accountId          = $transaction->account_id;
-            $result[$accountId] = $result[$accountId] ?? '0';
-            $result[$accountId] = bcadd($transaction->transaction_amount, $result[$accountId]);
-        }
-
-        return $result;
-    }
-
     /**
      * @param Collection $collection
      *
diff --git a/app/Generator/Report/Category/MultiYearReportGenerator.php b/app/Generator/Report/Category/MultiYearReportGenerator.php
index 62b0e32af9..0f57b6b888 100644
--- a/app/Generator/Report/Category/MultiYearReportGenerator.php
+++ b/app/Generator/Report/Category/MultiYearReportGenerator.php
@@ -17,7 +17,7 @@ namespace FireflyIII\Generator\Report\Category;
 /**
  * Class MultiYearReportGenerator
  *
- * @package FireflyIII\Generator\Report\Audit
+ * @package FireflyIII\Generator\Report\Category
  */
 class MultiYearReportGenerator extends MonthReportGenerator
 {
diff --git a/app/Generator/Report/Category/YearReportGenerator.php b/app/Generator/Report/Category/YearReportGenerator.php
index a118c4c5b0..e4f62dba0f 100644
--- a/app/Generator/Report/Category/YearReportGenerator.php
+++ b/app/Generator/Report/Category/YearReportGenerator.php
@@ -17,7 +17,7 @@ namespace FireflyIII\Generator\Report\Category;
 /**
  * Class YearReportGenerator
  *
- * @package FireflyIII\Generator\Report\Audit
+ * @package FireflyIII\Generator\Report\Category
  */
 class YearReportGenerator extends MonthReportGenerator
 {
diff --git a/app/Generator/Report/Support.php b/app/Generator/Report/Support.php
index 573129ef97..9125031579 100644
--- a/app/Generator/Report/Support.php
+++ b/app/Generator/Report/Support.php
@@ -80,4 +80,124 @@ class Support
         return $result;
     }
 
+    /**
+     * @param Collection $collection
+     * @param int        $sortFlag
+     *
+     * @return array
+     */
+    protected function getAverages(Collection $collection, int $sortFlag): array
+    {
+        $result = [];
+        /** @var Transaction $transaction */
+        foreach ($collection as $transaction) {
+            // opposing name and ID:
+            $opposingId = $transaction->opposing_account_id;
+
+            // is not set?
+            if (!isset($result[$opposingId])) {
+                $name                = $transaction->opposing_account_name;
+                $result[$opposingId] = [
+                    'name'    => $name,
+                    'count'   => 1,
+                    'id'      => $opposingId,
+                    'average' => $transaction->transaction_amount,
+                    'sum'     => $transaction->transaction_amount,
+                ];
+                continue;
+            }
+            $result[$opposingId]['count']++;
+            $result[$opposingId]['sum']     = bcadd($result[$opposingId]['sum'], $transaction->transaction_amount);
+            $result[$opposingId]['average'] = bcdiv($result[$opposingId]['sum'], strval($result[$opposingId]['count']));
+        }
+
+        // sort result by average:
+        $average = [];
+        foreach ($result as $key => $row) {
+            $average[$key] = floatval($row['average']);
+        }
+
+        array_multisort($average, $sortFlag, $result);
+
+        return $result;
+    }
+
+    /**
+     * @SuppressWarnings(PHPMD.CyclomaticComplexity) // it's exactly five.
+     * @param array $spent
+     * @param array $earned
+     *
+     * @return array
+     */
+    protected function getObjectSummary(array $spent, array $earned): array
+    {
+        $return = [];
+
+        /**
+         * @var int    $accountId
+         * @var string $entry
+         */
+        foreach ($spent as $objectId => $entry) {
+            if (!isset($return[$objectId])) {
+                $return[$objectId] = ['spent' => 0, 'earned' => 0];
+            }
+
+            $return[$objectId]['spent'] = $entry;
+        }
+        unset($entry);
+
+        /**
+         * @var int    $accountId
+         * @var string $entry
+         */
+        foreach ($earned as $objectId => $entry) {
+            if (!isset($return[$objectId])) {
+                $return[$objectId] = ['spent' => 0, 'earned' => 0];
+            }
+
+            $return[$objectId]['earned'] = $entry;
+        }
+
+
+        return $return;
+    }
+
+    /**
+     * @return Collection
+     */
+    public function getTopExpenses(): Collection
+    {
+        $transactions = $this->getExpenses()->sortBy('transaction_amount');
+
+        return $transactions;
+    }
+
+    /**
+     * @return Collection
+     */
+    public function getTopIncome(): Collection
+    {
+        $transactions = $this->getIncome()->sortByDesc('transaction_amount');
+
+        return $transactions;
+    }
+
+    /**
+     * @param Collection $collection
+     *
+     * @return array
+     */
+    protected function summarizeByAccount(Collection $collection): array
+    {
+        $result = [];
+        /** @var Transaction $transaction */
+        foreach ($collection as $transaction) {
+            $accountId          = $transaction->account_id;
+            $result[$accountId] = $result[$accountId] ?? '0';
+            $result[$accountId] = bcadd($transaction->transaction_amount, $result[$accountId]);
+        }
+
+        return $result;
+    }
+
 }
diff --git a/app/Generator/Report/Tag/MonthReportGenerator.php b/app/Generator/Report/Tag/MonthReportGenerator.php
new file mode 100644
index 0000000000..d58598c8f9
--- /dev/null
+++ b/app/Generator/Report/Tag/MonthReportGenerator.php
@@ -0,0 +1,219 @@
+expenses = new Collection;
+        $this->income   = new Collection;
+    }
+
+    /**
+     * @return string
+     */
+    public function generate(): string
+    {
+        $accountIds      = join(',', $this->accounts->pluck('id')->toArray());
+        $tagTags         = join(',', $this->tags->pluck('tag')->toArray());
+        $reportType      = 'tag';
+        $expenses        = $this->getExpenses();
+        $income          = $this->getIncome();
+        $accountSummary  = $this->getObjectSummary($this->summarizeByAccount($expenses), $this->summarizeByAccount($income));
+        $tagSummary      = $this->getObjectSummary($this->summarizeByTag($expenses), $this->summarizeByTag($income));
+        $averageExpenses = $this->getAverages($expenses, SORT_ASC);
+        $averageIncome   = $this->getAverages($income, SORT_DESC);
+        $topExpenses     = $this->getTopExpenses();
+        $topIncome       = $this->getTopIncome();
+
+
+        // render!
+        return view(
+            'reports.tag.month', compact(
+                                   'accountIds', 'tagTags', 'reportType', 'accountSummary', 'tagSummary', 'averageExpenses', 'averageIncome', 'topIncome',
+                                   'topExpenses'
+                               )
+        )->with('start', $this->start)->with('end', $this->end)->with('tags', $this->tags)->with('accounts', $this->accounts)->render();
+    }
+
+    /**
+     * @param Collection $accounts
+     *
+     * @return ReportGeneratorInterface
+     */
+    public function setAccounts(Collection $accounts): ReportGeneratorInterface
+    {
+        $this->accounts = $accounts;
+
+        return $this;
+    }
+
+    /**
+     * @param Collection $budgets
+     *
+     * @return ReportGeneratorInterface
+     */
+    public function setBudgets(Collection $budgets): ReportGeneratorInterface
+    {
+        return $this;
+    }
+
+    /**
+     * @param Collection $categories
+     *
+     * @return ReportGeneratorInterface
+     */
+    public function setCategories(Collection $categories): ReportGeneratorInterface
+    {
+        return $this;
+    }
+
+    /**
+     * @param Carbon $date
+     *
+     * @return ReportGeneratorInterface
+     */
+    public function setEndDate(Carbon $date): ReportGeneratorInterface
+    {
+        $this->end = $date;
+
+        return $this;
+    }
+
+    /**
+     * @param Carbon $date
+     *
+     * @return ReportGeneratorInterface
+     */
+    public function setStartDate(Carbon $date): ReportGeneratorInterface
+    {
+        $this->start = $date;
+
+        return $this;
+    }
+
+    /**
+     * @param Collection $tags
+     *
+     * @return ReportGeneratorInterface
+     */
+    public function setTags(Collection $tags): ReportGeneratorInterface
+    {
+        $this->tags = $tags;
+
+        return $this;
+    }
+
+    /**
+     * @return Collection
+     */
+    protected function getExpenses(): Collection
+    {
+        if ($this->expenses->count() > 0) {
+            Log::debug('Return previous set of expenses.');
+
+            return $this->expenses;
+        }
+
+        /** @var JournalCollectorInterface $collector */
+        $collector = app(JournalCollectorInterface::class);
+        $collector->setAccounts($this->accounts)->setRange($this->start, $this->end)
+                  ->setTypes([TransactionType::WITHDRAWAL, TransactionType::TRANSFER])
+                  ->setTags($this->tags)->withOpposingAccount()->disableFilter();
+
+        $accountIds     = $this->accounts->pluck('id')->toArray();
+        $transactions   = $collector->getJournals();
+        $transactions   = self::filterExpenses($transactions, $accountIds);
+        $this->expenses = $transactions;
+
+        return $transactions;
+    }
+
+    /**
+     * @return Collection
+     */
+    protected function getIncome(): Collection
+    {
+        if ($this->income->count() > 0) {
+            return $this->income;
+        }
+
+        /** @var JournalCollectorInterface $collector */
+        $collector = app(JournalCollectorInterface::class);
+        $collector->setAccounts($this->accounts)->setRange($this->start, $this->end)
+                  ->setTypes([TransactionType::DEPOSIT, TransactionType::TRANSFER])
+                  ->setTags($this->tags)->withOpposingAccount();
+        $accountIds   = $this->accounts->pluck('id')->toArray();
+        $transactions = $collector->getJournals();
+        $transactions = self::filterIncome($transactions, $accountIds);
+        $this->income = $transactions;
+
+        return $transactions;
+    }
+
+    /**
+     * @param Collection $collection
+     *
+     * @return array
+     */
+    protected function summarizeByTag(Collection $collection): array
+    {
+        $result = [];
+        /** @var Transaction $transaction */
+        foreach ($collection as $transaction) {
+            $journal     = $transaction->transactionJournal;
+            $journalTags = $journal->tags;
+            /** @var Tag $journalTag */
+            foreach ($journalTags as $journalTag) {
+                $journalTagId          = $journalTag->id;
+                $result[$journalTagId] = $result[$journalTagId] ?? '0';
+                $result[$journalTagId] = bcadd($transaction->transaction_amount, $result[$journalTagId]);
+            }
+        }
+
+        return $result;
+    }
+}
diff --git a/app/Generator/Report/Tag/MultiYearReportGenerator.php b/app/Generator/Report/Tag/MultiYearReportGenerator.php
new file mode 100644
index 0000000000..3f92a96e7a
--- /dev/null
+++ b/app/Generator/Report/Tag/MultiYearReportGenerator.php
@@ -0,0 +1,25 @@
+query->leftJoin('tag_transaction_journal', 'tag_transaction_journal.transaction_journal_id', '=', 'transaction_journals.id');
         }
     }
+
+    /**
+     * @param Collection $tags
+     *
+     * @return JournalCollectorInterface
+     */
+    public function setTags(Collection $tags): JournalCollectorInterface
+    {
+        $this->joinTagTables();
+        $tagIds = $tags->pluck('id')->toArray();
+        $this->query->whereIn('tag_transaction_journal.tag_id', $tagIds);
+
+        return $this;
+    }
 }
diff --git a/app/Helpers/Collector/JournalCollectorInterface.php b/app/Helpers/Collector/JournalCollectorInterface.php
index 80e41eb781..05306699a7 100644
--- a/app/Helpers/Collector/JournalCollectorInterface.php
+++ b/app/Helpers/Collector/JournalCollectorInterface.php
@@ -141,6 +141,13 @@ interface JournalCollectorInterface
      */
     public function setTag(Tag $tag): JournalCollectorInterface;
 
+    /**
+     * @param Collection $tags
+     *
+     * @return JournalCollectorInterface
+     */
+    public function setTags(Collection $tags): JournalCollectorInterface;
+
     /**
      * @param array $types
      *
diff --git a/app/Http/Controllers/Chart/CategoryReportController.php b/app/Http/Controllers/Chart/CategoryReportController.php
index 94f6cfb370..faffd3124f 100644
--- a/app/Http/Controllers/Chart/CategoryReportController.php
+++ b/app/Http/Controllers/Chart/CategoryReportController.php
@@ -331,22 +331,4 @@ class CategoryReportController extends Controller
 
         return $grouped;
     }
-
-    /**
-     * @param Collection $set
-     *
-     * @return array
-     */
-    private function groupByOpposingAccount(Collection $set): array
-    {
-        $grouped = [];
-        /** @var Transaction $transaction */
-        foreach ($set as $transaction) {
-            $accountId           = $transaction->opposing_account_id;
-            $grouped[$accountId] = $grouped[$accountId] ?? '0';
-            $grouped[$accountId] = bcadd($transaction->transaction_amount, $grouped[$accountId]);
-        }
-
-        return $grouped;
-    }
 }
diff --git a/app/Http/Controllers/Chart/TagReportController.php b/app/Http/Controllers/Chart/TagReportController.php
new file mode 100644
index 0000000000..afa6fb8c31
--- /dev/null
+++ b/app/Http/Controllers/Chart/TagReportController.php
@@ -0,0 +1,216 @@
+generator = app(GeneratorInterface::class);
+    }
+
+    /**
+     * @param Collection $accounts
+     * @param Collection $tags
+     * @param Carbon     $start
+     * @param Carbon     $end
+     *
+     * @return \Illuminate\Http\JsonResponse
+     */
+    public function mainChart(Collection $accounts, Collection $tags, Carbon $start, Carbon $end)
+    {
+        $cache = new CacheProperties;
+        $cache->addProperty('chart.category.report.main');
+        $cache->addProperty($accounts);
+        $cache->addProperty($tags);
+        $cache->addProperty($start);
+        $cache->addProperty($end);
+        if ($cache->has()) {
+            return Response::json($cache->get());
+        }
+
+        $format       = Navigation::preferredCarbonLocalizedFormat($start, $end);
+        $function     = Navigation::preferredEndOfPeriod($start, $end);
+        $chartData    = [];
+        $currentStart = clone $start;
+
+        // prep chart data:
+        foreach ($tags as $tag) {
+            $chartData[$tag->id . '-in']  = [
+                'label'   => $tag->tag . ' (' . strtolower(strval(trans('firefly.income'))) . ')',
+                'type'    => 'bar',
+                'yAxisID' => 'y-axis-0',
+                'entries' => [],
+            ];
+            $chartData[$tag->id . '-out'] = [
+                'label'   => $tag->tag . ' (' . strtolower(strval(trans('firefly.expenses'))) . ')',
+                'type'    => 'bar',
+                'yAxisID' => 'y-axis-0',
+                'entries' => [],
+            ];
+            // total in, total out:
+            $chartData[$tag->id . '-total-in']  = [
+                'label'   => $tag->tag . ' (' . strtolower(strval(trans('firefly.sum_of_income'))) . ')',
+                'type'    => 'line',
+                'fill'    => false,
+                'yAxisID' => 'y-axis-1',
+                'entries' => [],
+            ];
+            $chartData[$tag->id . '-total-out'] = [
+                'label'   => $tag->tag . ' (' . strtolower(strval(trans('firefly.sum_of_expenses'))) . ')',
+                'type'    => 'line',
+                'fill'    => false,
+                'yAxisID' => 'y-axis-1',
+                'entries' => [],
+            ];
+        }
+        $sumOfIncome  = [];
+        $sumOfExpense = [];
+
+        while ($currentStart < $end) {
+            $currentEnd = clone $currentStart;
+            $currentEnd = $currentEnd->$function();
+            $expenses   = $this->groupByTag($this->getExpenses($accounts, $tags, $currentStart, $currentEnd));
+            $income     = $this->groupByTag($this->getIncome($accounts, $tags, $currentStart, $currentEnd));
+            $label      = $currentStart->formatLocalized($format);
+
+            /** @var Tag $tag */
+            foreach ($tags as $tag) {
+                $labelIn        = $tag->id . '-in';
+                $labelOut       = $tag->id . '-out';
+                $labelSumIn     = $tag->id . '-total-in';
+                $labelSumOut    = $tag->id . '-total-out';
+                $currentIncome  = $income[$tag->id] ?? '0';
+                $currentExpense = $expenses[$tag->id] ?? '0';
+
+
+                // add to sum:
+                $sumOfIncome[$tag->id]  = $sumOfIncome[$tag->id] ?? '0';
+                $sumOfExpense[$tag->id] = $sumOfExpense[$tag->id] ?? '0';
+                $sumOfIncome[$tag->id]  = bcadd($sumOfIncome[$tag->id], $currentIncome);
+                $sumOfExpense[$tag->id] = bcadd($sumOfExpense[$tag->id], $currentExpense);
+
+                // add to chart:
+                $chartData[$labelIn]['entries'][$label]     = $currentIncome;
+                $chartData[$labelOut]['entries'][$label]    = $currentExpense;
+                $chartData[$labelSumIn]['entries'][$label]  = $sumOfIncome[$tag->id];
+                $chartData[$labelSumOut]['entries'][$label] = $sumOfExpense[$tag->id];
+            }
+            $currentStart = clone $currentEnd;
+            $currentStart->addDay();
+        }
+        // remove all empty entries to prevent cluttering:
+        $newSet = [];
+        foreach ($chartData as $key => $entry) {
+            if (!array_sum($entry['entries']) == 0) {
+                $newSet[$key] = $chartData[$key];
+            }
+        }
+        if (count($newSet) === 0) {
+            $newSet = $chartData;
+        }
+        $data = $this->generator->multiSet($newSet);
+        $cache->store($data);
+
+        return Response::json($data);
+    }
+
+
+    /**
+     * @param Collection $accounts
+     * @param Collection $tags
+     * @param Carbon     $start
+     * @param Carbon     $end
+     *
+     * @return Collection
+     */
+    private function getExpenses(Collection $accounts, Collection $tags, Carbon $start, Carbon $end): Collection
+    {
+        /** @var JournalCollectorInterface $collector */
+        $collector = app(JournalCollectorInterface::class);
+        $collector->setAccounts($accounts)->setRange($start, $end)->setTypes([TransactionType::WITHDRAWAL, TransactionType::TRANSFER])
+                  ->setTags($tags)->withOpposingAccount()->disableFilter();
+        $accountIds   = $accounts->pluck('id')->toArray();
+        $transactions = $collector->getJournals();
+        $set          = MonthReportGenerator::filterExpenses($transactions, $accountIds);
+
+        return $set;
+    }
+
+    /**
+     * @param Collection $accounts
+     * @param Collection $tags
+     * @param Carbon     $start
+     * @param Carbon     $end
+     *
+     * @return Collection
+     */
+    private function getIncome(Collection $accounts, Collection $tags, Carbon $start, Carbon $end): Collection
+    {
+        /** @var JournalCollectorInterface $collector */
+        $collector = app(JournalCollectorInterface::class);
+        $collector->setAccounts($accounts)->setRange($start, $end)->setTypes([TransactionType::DEPOSIT, TransactionType::TRANSFER])
+                  ->setTags($tags)->withOpposingAccount();
+        $accountIds   = $accounts->pluck('id')->toArray();
+        $transactions = $collector->getJournals();
+        $set          = MonthReportGenerator::filterIncome($transactions, $accountIds);
+
+        return $set;
+    }
+
+    /**
+     * @param Collection $set
+     *
+     * @return array
+     */
+    private function groupByTag(Collection $set): array
+    {
+        // group by category ID:
+        $grouped = [];
+        /** @var Transaction $transaction */
+        foreach ($set as $transaction) {
+            $journal     = $transaction->transactionJournal;
+            $journalTags = $journal->tags;
+            /** @var Tag $journalTag */
+            foreach ($journalTags as $journalTag) {
+                $journalTagId           = $journalTag->id;
+                $grouped[$journalTagId] = $grouped[$journalTagId] ?? '0';
+                $grouped[$journalTagId] = bcadd($transaction->transaction_amount, $grouped[$journalTagId]);
+            }
+        }
+
+        return $grouped;
+    }
+
+}
\ No newline at end of file
diff --git a/app/Http/breadcrumbs.php b/app/Http/breadcrumbs.php
index 05bf0acb56..62d7311e0a 100644
--- a/app/Http/breadcrumbs.php
+++ b/app/Http/breadcrumbs.php
@@ -556,6 +556,19 @@ Breadcrumbs::register(
 }
 );
 
+Breadcrumbs::register(
+    'reports.report.tag', function (BreadCrumbGenerator $breadcrumbs, string $accountIds, string $tagTags, Carbon $start, Carbon $end) {
+    $breadcrumbs->parent('reports.index');
+
+    $monthFormat = (string)trans('config.month_and_day');
+    $startString = $start->formatLocalized($monthFormat);
+    $endString   = $end->formatLocalized($monthFormat);
+    $title       = (string)trans('firefly.report_tag', ['start' => $startString, 'end' => $endString]);
+
+    $breadcrumbs->push($title, route('reports.report.tag', [$accountIds, $tagTags, $start->format('Ymd'), $end->format('Ymd')]));
+}
+);
+
 Breadcrumbs::register(
     'reports.report.category', function (BreadCrumbGenerator $breadcrumbs, string $accountIds, string $categoryIds, Carbon $start, Carbon $end) {
     $breadcrumbs->parent('reports.index');
diff --git a/public/js/ff/reports/tag/all.js b/public/js/ff/reports/tag/all.js
new file mode 100644
index 0000000000..25a412d1c5
--- /dev/null
+++ b/public/js/ff/reports/tag/all.js
@@ -0,0 +1,10 @@
+/*
+ * all.js
+ * Copyright (C) 2016 thegrumpydictator@gmail.com
+ *
+ * This software may be modified and distributed under the terms of the
+ * Creative Commons Attribution-ShareAlike 4.0 International License.
+ *
+ * See the LICENSE file for details.
+ */
+
diff --git a/public/js/ff/reports/tag/month.js b/public/js/ff/reports/tag/month.js
new file mode 100644
index 0000000000..1f1584655c
--- /dev/null
+++ b/public/js/ff/reports/tag/month.js
@@ -0,0 +1,66 @@
+/*
+ * month.js
+ * Copyright (c) 2017 thegrumpydictator@gmail.com
+ * This software may be modified and distributed under the terms of the Creative Commons Attribution-ShareAlike 4.0 International License.
+ *
+ * See the LICENSE file for details.
+ */
+
+/** global: tagIncomeUri, tagExpenseUri, accountIncomeUri, accountExpenseUri, tagBudgetUri, tagCategoryUri, mainUri */
+
+$(function () {
+    "use strict";
+    drawChart();
+
+    $('#tags-in-pie-chart-checked').on('change', function () {
+        redrawPieChart('tags-in-pie-chart', tagIncomeUri);
+    });
+
+    $('#tags-out-pie-chart-checked').on('change', function () {
+        redrawPieChart('tags-out-pie-chart', tagExpenseUri);
+    });
+
+    $('#accounts-in-pie-chart-checked').on('change', function () {
+        redrawPieChart('accounts-in-pie-chart', accountIncomeUri);
+    });
+
+    $('#accounts-out-pie-chart-checked').on('change', function () {
+        redrawPieChart('accounts-out-pie-chart', accountExpenseUri);
+    });
+
+    // two extra charts:
+    pieChart(tagBudgetUri, 'budgets-out-pie-chart');
+    pieChart(tagCategoryUri, 'categories-out-pie-chart');
+
+});
+
+
+function drawChart() {
+    "use strict";
+
+    // month view:
+    doubleYChart(mainUri, 'in-out-chart');
+
+    // draw pie chart of income, depending on "show other transactions too":
+    redrawPieChart('tags-in-pie-chart', tagIncomeUri);
+    redrawPieChart('tags-out-pie-chart', tagExpenseUri);
+    redrawPieChart('accounts-in-pie-chart', accountIncomeUri);
+    redrawPieChart('accounts-out-pie-chart', accountExpenseUri);
+
+
+}
+
+function redrawPieChart(container, uri) {
+    "use strict";
+    var checkbox = $('#' + container + '-checked');
+
+    var others = '0';
+    // check if box is checked:
+    if (checkbox.prop('checked')) {
+        others = '1';
+    }
+    uri = uri.replace('OTHERS', others);
+
+    pieChart(uri, container);
+
+}
diff --git a/resources/lang/en_US/firefly.php b/resources/lang/en_US/firefly.php
index d4e5fb0c73..3fe45e6dd0 100644
--- a/resources/lang/en_US/firefly.php
+++ b/resources/lang/en_US/firefly.php
@@ -667,6 +667,7 @@ return [
     'report_audit'                               => 'Transaction history overview between :start and :end',
     'report_category'                            => 'Category report between :start and :end',
     'report_budget'                              => 'Budget report between :start and :end',
+    'report_tag'                                 => 'Tag report between :start and :end',
     'quick_link_reports'                         => 'Quick links',
     'quick_link_default_report'                  => 'Default financial report',
     'quick_link_audit_report'                    => 'Transaction history overview',
diff --git a/resources/views/reports/tag/month.twig b/resources/views/reports/tag/month.twig
new file mode 100644
index 0000000000..4ba5515c30
--- /dev/null
+++ b/resources/views/reports/tag/month.twig
@@ -0,0 +1,434 @@
+{% extends "./layout/default" %}
+
+{% block breadcrumbs %}
+    {{ Breadcrumbs.renderIfExists(Route.getCurrentRoute.getName, accountIds, tagTags, start, end) }}
+{% endblock %}
+
+{% block content %}
+
+    
+        
+            
+                
+                
+                    
+                        
+                        
+                            | {{ 'name'|_ }}+ | {{ 'earned'|_ }}+ | {{ 'spent'|_ }}+ | 
+                        
+                        
+                        {% for account in accounts %}
+                            
+                                | +                                    {{ account.name }}
++                                {% if accountSummary[account.id] %}
+ | {{ accountSummary[account.id].earned|formatAmount }}+                                {% else %}
+ | {{ 0|formatAmount }}+                                {% endif %}
+                                {% if accountSummary[account.id] %}
+ | {{ accountSummary[account.id].spent|formatAmount }}+                                {% else %}
+ | {{ 0|formatAmount }}+                                {% endif %}
+ | 
+                        {% endfor %}
+                        
+                    
+                
+            
+        
+        
+            
+                
+                
+                    
+                    
+                
+            
+        
+        
+            
+                
+                
+                    
+                    
+                
+            
+        
+        
+            
+                
+                
+                    
+                    Uitgaven per budget voor de gevonden transacties
+                
+            
+        
+    
+        
+            
+                
+                
+                    
+                        
+                        
+                            | {{ 'name'|_ }}+ | {{ 'earned'|_ }}+ | {{ 'spent'|_ }}+ | 
+                        
+                        
+                        {% for tag in tags %}
+                            
+                                | +                                    {{ tag.tag }}
++                                {% if tagSummary[tag.id] %}
+ | {{ tagSummary[tag.id].earned|formatAmount }}+                                {% else %}
+ | {{ 0|formatAmount }}+                                {% endif %}
+                                {% if tagSummary[tag.id] %}
+ | {{ tagSummary[tag.id].spent|formatAmount }}+                                {% else %}
+ | {{ 0|formatAmount }}+                                {% endif %}
+ | 
+                        {% endfor %}
+                        
+                    
+                
+            
+        
+        
+            
+                
+                
+                    
+                    
+                
+            
+        
+        
+            
+                
+                
+                    
+                    
+                
+            
+        
+
+        
+            
+                
+                
+                    
+                    Uitgaven per category voor de gevonden transacties
+                
+            
+        
+
+    
+        {% if averageExpenses|length > 0 %}
+            
+                
+                    
+                    
+                        
+                            
+                            
+                                | {{ 'account'|_ }}+ | {{ 'spent_average'|_ }}+ | {{ 'total'|_ }}+ | {{ 'transaction_count'|_ }}+ | 
+                            
+                            
+                            {% for row in averageExpenses %}
+                                {% if loop.index > listLength %}
+                                    
+                                {% else %}
+                                    
+                                {% endif %}
+                                | +                                    {{ row.name }}
++ | +                                    {{ row.average|formatAmount }}
++ | +                                    {{ row.sum|formatAmount }}
++ | +                                    {{ row.count }}
++ | 
+                            {% endfor %}
+                            
+                            
+                            {% if averageExpenses|length > listLength %}
+                                
+                                    | +                                        {{ trans('firefly.show_full_list',{number:incomeTopLength}) }}
++ | 
+                            {% endif %}
+                            
+                        
+                    
+                
+            
+        {% endif %}
+        {% if topExpenses.count > 0 %}
+            
+        {% endif %}
+    
+        {% if averageIncome|length > 0 %}
+            
+                
+                    
+                    
+                        
+                            
+                            
+                                | {{ 'account'|_ }}+ | {{ 'income_average'|_ }}+ | {{ 'total'|_ }}+ | {{ 'transaction_count'|_ }}+ | 
+                            
+                            
+                            {% for row in averageIncome %}
+                                
+                                    | +                                        {{ row.name }}
++ | +                                        {{ row.average|formatAmount }}
++ | +                                        {{ row.sum|formatAmount }}
++ | +                                        {{ row.count }}
++ | 
+                            {% endfor %}
+                            
+                        
+                    
+                
+            
+        {% endif %}
+        
+            {% if topIncome.count > 0 %}
+                
+            {% endif %}
+        
+